1 /*
2 ** OSSP lmtp2nntp - Mail to News Gateway
3 ** Copyright (c) 2001-2003 Ralf S. Engelschall <rse@engelschall.com>
4 ** Copyright (c) 2001-2003 The OSSP Project <http://www.ossp.org/>
5 ** Copyright (c) 2001-2003 Cable & Wireless Germany <http://www.cw.com/de/>
6 **
7 ** This file is part of OSSP lmtp2nntp, an LMTP speaking local
8 ** mailer which forwards mails as Usenet news articles via NNTP.
9 ** It can be found at http://www.ossp.org/pkg/tool/lmtp2nntp/.
10 **
11 ** This program is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License
13 ** as published by the Free Software Foundation; either version
14 ** 2.0 of the License, or (at your option) any later version.
15 **
16 ** This program is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
20 **
21 ** You should have received a copy of the GNU General Public License
22 ** along with this file; if not, write to the Free Software
23 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24 ** USA, or contact the OSSP project <ossp@ossp.org>.
25 **
26 ** lmtp2nntp_main.c: LMTP to NNTP main procedure
27 */
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <sys/utsname.h>
36 #include <sys/time.h>
37 #include <sys/types.h>
38 #include <sys/wait.h>
39 #include <sys/stat.h>
40 #include <signal.h>
41 #include <stdarg.h>
42
43 /* third party (included) */
44 #include "lmtp2nntp_argz.h"
45 #include "lmtp2nntp_shpat.h"
46 #include "lmtp2nntp_daemon.h"
47
48 /* third party (linked in) */
49 #include "ex.h"
50 #include "str.h"
51 #include "l2.h"
52 #include "sa.h"
53 #include "var.h"
54 #include "val.h"
55 #include "popt.h"
56
57 /* library version check (compile-time) */
58 #define L2_VERSION_HEX_REQ 0x001200
59 #define L2_VERSION_STR_REQ "0.1.0"
60 #define STR_VERSION_HEX_REQ 0x009206
61 #define STR_VERSION_STR_REQ "0.9.6"
62 #ifdef L2_VERSION_HEX
63 #if L2_VERSION_HEX < L2_VERSION_HEX_REQ
64 #error "require a newer version of OSSP L2"
65 #endif
66 #endif
67 #ifdef STR_VERSION_HEX
68 #if STR_VERSION_HEX < STR_VERSION_HEX_REQ
69 #error "require a newer version of OSSP Str"
70 #endif
71 #endif
72
73 /* own headers */
74 #include "lmtp2nntp_global.h"
75 #ifdef HAVE_CONFIG_H
76 #include "config.h"
77 #endif
78 #if defined(HAVE_DMALLOC_H) && defined(WITH_DMALLOC)
79 #include "dmalloc.h"
80 #endif
81 #include "lmtp2nntp_option.h"
82 #include "lmtp2nntp_config.h"
83 #include "lmtp2nntp_lmtp.h"
84 #include "lmtp2nntp_nntp.h"
85 #include "lmtp2nntp_msg.h"
86 #include "lmtp2nntp_common.h"
87 #include "sa.h"
88 #define _LMTP2NNTP_VERSION_C_AS_HEADER_
89 #include "lmtp2nntp_version.c"
90 #undef _LMTP2NNTP_VERSION_C_AS_HEADER_
91
92 #ifndef FALSE
93 #define FALSE (1 != 1)
94 #endif
95 #ifndef TRUE
96 #define TRUE (!FALSE)
97 #endif
98
99 #ifndef NUL
100 #define NUL '\0'
101 #endif
102
103 #define STDSTRLEN 512
104
105 static lmtp_rc_t lmtp_cb_lhlo(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx);
106 static lmtp_rc_t lmtp_cb_mail(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx);
107 static lmtp_rc_t lmtp_cb_rcpt(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx);
108 static lmtp_rc_t lmtp_cb_data(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx);
109 static lmtp_rc_t lmtp_cb_noop(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx);
110 static lmtp_rc_t lmtp_cb_rset(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx);
111 static lmtp_rc_t lmtp_cb_quit(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx);
112
113 static int helo_rfc0821domain(char *msg, char **domain);
114 static int helo_rfc1035domain(char *msg, char **domain);
115
116 static void catchsignal(int sig, ...);
117 static void initsession(struct session *session);
118 static void resetsession(struct session *session);
119 int groupmatch(char *, size_t, char *);
120
logbook(l2_channel_t * ch,l2_level_t level,const char * fmt,...)121 void logbook(l2_channel_t *ch, l2_level_t level, const char *fmt, ...)
122 {
123 va_list ap;
124 l2_channel_t *ch2 = NULL;
125
126 if (strchr(fmt, '$') == NULL) {
127 if (l2_channel_downstream(ch, &ch2) != L2_OK)
128 return;
129 ch = ch2;
130 }
131 va_start(ap, fmt);
132 l2_channel_vlog(ch, level, fmt, &ap);
133 va_end(ap);
134 return;
135 }
136
137 static var_syntax_t syntax_ctx = {
138 '\\', /* escape */
139 '$', /* varinit */
140 '{', /* startdelim */
141 '}', /* enddelim */
142 '[', /* startindex */
143 ']', /* endindex */
144 '#', /* current_index */
145 "a-zA-Z0-9.-" /* namechars */
146 };
147
ctx_lookup(var_t * var,void * _ctx,const char * var_ptr,size_t var_len,int var_idx,const char ** val_ptr,size_t * val_len,size_t * val_size)148 static var_rc_t ctx_lookup(
149 var_t *var,
150 void *_ctx,
151 const char *var_ptr, size_t var_len, int var_idx,
152 const char **val_ptr, size_t *val_len, size_t *val_size)
153 {
154 lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
155 var_rc_t rc;
156 char *cp;
157 optionval_t *ov;
158
159 rc = VAR_ERR_UNDEFINED_VARIABLE;
160 if (strncasecmp(var_ptr, "option.", strlen("option.")) == 0) {
161 cp = str_dupex(var_ptr, var_len);
162 if (val_get(ctx->val, cp, &ov) == VAL_OK) {
163 if ((var_idx == 0) && (ov->ndata == 1) && (ov->type == OPT_SINGLE)) { /* request first/only single value */
164 *val_ptr = ov->data.s;
165 *val_len = strlen(ov->data.s);
166 *val_size = 0;
167 rc = VAR_OK;
168 }
169 else if ((var_idx == 0) && (ov->ndata == 1) && (ov->type == OPT_FLAG)) { /* request first/only single value */
170 *val_ptr = ov->data.f == TRUE ? "yes" : "no";
171 *val_len = strlen(ov->data.s);
172 *val_size = 0;
173 rc = VAR_OK;
174 }
175 else if ((var_idx < ov->ndata) && (ov->type == OPT_MULTI)) { /* request second+ from multi value */
176 *val_ptr = ov->data.m[var_idx];
177 *val_len = strlen(ov->data.m[var_idx]);
178 *val_size = 0;
179 rc = VAR_OK;
180 }
181 }
182 free(cp);
183 }
184 else if ( (strncasecmp(var_ptr, "msg.header.", strlen("msg.header.")) == 0)
185 && (ctx->msg != NULL)
186 ) {
187 headerdata_t *hdI;
188 int n;
189 cp = str_dupex(var_ptr + strlen("msg.header."), var_len - strlen("msg.header.") + 1);
190 n = strlen(cp);
191 cp[n]= ':';
192 cp[n + 1] = NUL;
193 for (hdI = ctx->msg->hdFirst; hdI != NULL; hdI = hdI->next) { /* for each header */
194 if (hdI->name == NULL || strlen(hdI->name) == 0)
195 continue;
196 if (strcasecmp(cp, hdI->name) == 0)
197 break;
198 }
199 if (hdI != NULL) {
200 if ((var_idx == 0) && (hdI->ndata == 1)) { /* request first/only single value */
201 *val_ptr = hdI->data.s;
202 *val_len = strlen(hdI->data.s);
203 *val_size = 0;
204 rc = VAR_OK;
205 }
206 else if (var_idx < hdI->ndata) { /* request from multi value */
207 *val_ptr = hdI->data.m[var_idx];
208 *val_len = strlen(hdI->data.m[var_idx]);
209 *val_size = 0;
210 rc = VAR_OK;
211 }
212 }
213 free(cp);
214 }
215
216 return rc;
217 }
218
219 static void lmtp_gfs_ns(struct ns *);
220 static void lmtp_gfs_lhlo(lmtp2nntp_t *);
221 static void lmtp_gfs_rset(lmtp2nntp_t *);
222 static void lmtp_gfs_quit(lmtp2nntp_t *);
223
sa2errno(sa_rc_t rv)224 static void sa2errno(sa_rc_t rv)
225 {
226 switch (rv) {
227 case SA_OK: errno = 0; break;
228 case SA_ERR_EOF: errno = 0; break;
229 case SA_ERR_SYS: break;
230 case SA_ERR_ARG: errno = EINVAL; break;
231 case SA_ERR_USE: errno = EINVAL; break;
232 case SA_ERR_MTC: errno = ENOENT; break;
233 case SA_ERR_MEM: errno = ENOMEM; break;
234 case SA_ERR_IMP: errno = ENOSYS; break;
235 case SA_ERR_TMT: errno = EIO; break;
236 case SA_ERR_NET: errno = EIO; break;
237 case SA_ERR_FMT: errno = EIO; break;
238 case SA_ERR_INT: errno = EIO; break;
239 default: errno = EIO;
240 }
241 }
242
hook_lmtp_read(void * _ctx,void * buf,size_t nbytes)243 static ssize_t hook_lmtp_read(void *_ctx, void *buf, size_t nbytes)
244 {
245 lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
246 ssize_t rc;
247 size_t n;
248 sa_rc_t rv;
249
250 if (ctx->saIO != NULL) {
251 if ((rv = sa_read(ctx->saIO, buf, nbytes, &n)) != SA_OK) {
252 if (rv == SA_ERR_SYS)
253 logbook(ctx->l2, L2_LEVEL_DEBUG, "hook_lmtp_read() sa_read failed with \"%s\" (%d) %s", sa_error(rv), errno, strerror(errno));
254 else
255 logbook(ctx->l2, L2_LEVEL_DEBUG, "hook_lmtp_read() sa_read failed with \"%s\"", sa_error(rv));
256 if (rv == SA_ERR_EOF)
257 rc = 0;
258 else
259 rc = -1;
260 sa2errno(rv);
261 }
262 else
263 rc = (ssize_t)n;
264 }
265 else {
266 rc = read(ctx->fdIOi, buf, nbytes);
267 if (rc == -1)
268 logbook(ctx->l2, L2_LEVEL_DEBUG, "hook_lmtp_read() read failed with (%d) %s", errno, strerror(errno));
269 }
270 if (rc == -1)
271 logbook(ctx->l2, L2_LEVEL_TRACE, "LMTP read error: %m");
272 else
273 logbook(ctx->l2, L2_LEVEL_TRACE, "LMTP %5d << \"%{text}D\"", rc, buf, rc);
274 logbook(ctx->l2, L2_LEVEL_DEBUG, "hook_lmtp_read() return, rc=%d", rc);
275 return rc;
276 }
277
hook_lmtp_write(void * _ctx,const void * buf,size_t nbytes)278 static ssize_t hook_lmtp_write(void *_ctx, const void *buf, size_t nbytes)
279 {
280 lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
281 ssize_t rc;
282 size_t n;
283 sa_rc_t rv;
284
285 logbook(ctx->l2, L2_LEVEL_TRACE, "LMTP %5d >> \"%{text}D\"", nbytes, buf, nbytes);
286 if (ctx->saIO != NULL) {
287 if ((rv = sa_write(ctx->saIO, buf, nbytes, &n)) != SA_OK) {
288 if (rv == SA_ERR_SYS)
289 logbook(ctx->l2, L2_LEVEL_DEBUG, "hook_lmtp_write() sa_write failed with \"%s\" (%d) %s", sa_error(rv), errno, strerror(errno));
290 else
291 logbook(ctx->l2, L2_LEVEL_DEBUG, "hook_lmtp_write() sa_write failed with \"%s\"", sa_error(rv));
292 rc = -1;
293 sa2errno(rv);
294 }
295 else
296 rc = (ssize_t)n;
297 }
298 else {
299 rc = write(ctx->fdIOo, buf, nbytes);
300 if (rc == -1)
301 logbook(ctx->l2, L2_LEVEL_DEBUG, "hook_lmtp_write() write failed with (%d) %s", errno, strerror(errno));
302 }
303 if (rc == -1)
304 logbook(ctx->l2, L2_LEVEL_TRACE, "LMTP write error");
305 return rc;
306 }
307
hook_nntp_read(void * _ctx,void * buf,size_t nbytes)308 static ssize_t hook_nntp_read(void *_ctx, void *buf, size_t nbytes)
309 {
310 struct ns *ctx = (struct ns *)_ctx;
311 ssize_t rc;
312 size_t n;
313 sa_rc_t rv;
314
315 if ((rv = sa_read(ctx->sa, buf, nbytes, &n)) != SA_OK) {
316 if (rv == SA_ERR_SYS)
317 logbook(ctx->l2, L2_LEVEL_DEBUG, "hook_lmtp_read() sa_read failed with \"%s\" (%d) %s", sa_error(rv), errno, strerror(errno));
318 else
319 logbook(ctx->l2, L2_LEVEL_DEBUG, "hook_lmtp_read() sa_read failed with \"%s\"", sa_error(rv));
320 if (rv == SA_ERR_EOF)
321 rc = 0;
322 else
323 rc = -1;
324 sa2errno(rv);
325 }
326 else
327 rc = (ssize_t)n;
328 if (rc == -1)
329 logbook(ctx->l2, L2_LEVEL_TRACE, "NNTP read error: %m");
330 else
331 logbook(ctx->l2, L2_LEVEL_TRACE, "NNTP %5d << \"%{text}D\"", rc, buf, rc);
332 return rc;
333 }
334
hook_nntp_write(void * _ctx,const void * buf,size_t nbytes)335 static ssize_t hook_nntp_write(void *_ctx, const void *buf, size_t nbytes)
336 {
337 struct ns *ctx = (struct ns *)_ctx;
338 ssize_t rc;
339 size_t n;
340 sa_rc_t rv;
341
342 logbook(ctx->l2, L2_LEVEL_TRACE, "NNTP %5d >> \"%{text}D\"", nbytes, buf, nbytes);
343 if ((rv = sa_write(ctx->sa, buf, nbytes, &n)) != SA_OK) {
344 if (rv == SA_ERR_SYS)
345 logbook(ctx->l2, L2_LEVEL_DEBUG, "hook_nntp_write() sa_write failed with \"%s\" (%d) %s", sa_error(rv), errno, strerror(errno));
346 else
347 logbook(ctx->l2, L2_LEVEL_DEBUG, "hook_nntp_write() sa_write failed with \"%s\"", sa_error(rv));
348 rc = -1;
349 sa2errno(rv);
350 }
351 else
352 rc = (ssize_t)n;
353 if (rc == -1)
354 logbook(ctx->l2, L2_LEVEL_TRACE, "NNTP write error");
355 return rc;
356 }
357
catchsignal(int sig,...)358 static void catchsignal(int sig, ...)
359 {
360 va_list ap;
361 static lmtp2nntp_t *ctx = NULL;
362 pid_t pid;
363
364 if(sig == 0) {
365 va_start(ap, sig);
366 if ((ctx = va_arg(ap, lmtp2nntp_t *)) == NULL)
367 exit(ERR_EXECUTION);
368 logbook(ctx->l2, L2_LEVEL_TRACE, "catching and logging signals now");
369 va_end(ap);
370 return;
371 }
372 if (ctx != NULL) {
373 switch (sig) {
374 case SIGCHLD:
375 logbook(ctx->l2, L2_LEVEL_NOTICE, "caught signal %d - wait for child", sig);
376 pid = wait(NULL);
377 ctx->active_childs--;
378 logbook(ctx->l2, L2_LEVEL_NOTICE, "caught signal %d - child [%ld] terminated", sig, (long)pid);
379 signal(sig, (void(*)())catchsignal);
380 return;
381 case SIGUSR1:
382 logbook(ctx->l2, L2_LEVEL_NOTICE, "caught signal %d - flush logging stream", sig);
383 l2_channel_flush(ctx->l2);
384 signal(sig, (void(*)())catchsignal);
385 return;
386 case SIGHUP:
387 case SIGINT:
388 case SIGQUIT:
389 logbook(ctx->l2, L2_LEVEL_NOTICE, "caught signal %d - exit - no more logging", sig);
390 break;
391 default:
392 logbook(ctx->l2, L2_LEVEL_PANIC, "CAUGHT SIGNAL %d - EXIT - NO MORE LOGGING", sig);
393 }
394 l2_channel_destroy(ctx->l2);
395 l2_env_destroy(ctx->l2_env);
396 }
397 exit(ERR_EXECUTION);
398 }
399
main(int argc,char ** argv)400 int main(int argc, char **argv)
401 {
402 int rc;
403 lmtp_t *lmtp = NULL;
404 lmtp_io_t lmtp_io;
405 lmtp2nntp_t *ctx = NULL;
406 int bOk;
407 int i; /* general purpose scratch int, index ... */
408 pid_t pid;
409 FILE *fd;
410 lmtp2nntp_option_t *o;
411
412 /* drop effective uid/gid privileges */
413 seteuid(getuid());
414 setegid(getgid());
415
416 /* use unbuffered stdio */
417 setvbuf(stdin, NULL, _IONBF, 0);
418 setvbuf(stdout, NULL, _IONBF, 0);
419 setvbuf(stderr, NULL, _IONBF, 0);
420
421 /* library version check (run-time) */
422 if (l2_version.v_hex < L2_VERSION_HEX_REQ) {
423 fprintf(stderr, "require OSSP L2 >= %s, found %s\n", L2_VERSION_STR_REQ, L2_VERSION_STR);
424 CU(ERR_EXECUTION);
425 }
426 if (str_version.v_hex < STR_VERSION_HEX_REQ) {
427 fprintf(stderr, "require OSSP Str >= %s, found %s\n", STR_VERSION_STR_REQ, STR_VERSION_STR);
428 CU(ERR_EXECUTION);
429 }
430
431 /* create application context. fields are initialized to values that allow
432 * detection of dynamic allocated resources which must be freed up for
433 * graceful cleanup. These values are not necessarily useful application
434 * defaults. Those defaults must be configured in lmtp2nntp_option.c
435 * through option_register() calls */
436 if ((ctx = (lmtp2nntp_t *)malloc(sizeof(lmtp2nntp_t))) == NULL)
437 CU(ERR_EXECUTION);
438 ctx->ctx.vp = ctx;
439 ctx->prival = NULL;
440 ctx->val = NULL;
441 ctx->progname = NULL;
442 ctx->option_groupmode = GROUPMODE_UNDEF;
443 ctx->option_operationmode = OPERATIONMODE_UNDEF;
444 ctx->option_operationmodefakestatus = NULL;
445 ctx->option_operationmodefakedsn = NULL; /* is joined to fakestatus in a single malloc(3) */
446 ctx->option_maxmessagesize = 0;
447 ctx->option_firstheaderrule = NULL;
448 ctx->option_timeout_lmtp_accept = 0;
449 ctx->option_timeout_lmtp_read = 0;
450 ctx->option_timeout_lmtp_write = 0;
451 ctx->option_timeout_nntp_connect = 0;
452 ctx->option_timeout_nntp_read = 0;
453 ctx->option_timeout_nntp_write = 0;
454 ctx->option_nodename = NULL;
455 ctx->option_mailfrom = NULL;
456 ctx->option_restrictheader = NULL;
457 ctx->option_pidfile = NULL;
458 ctx->option_killflag = FALSE;
459 ctx->option_uid = getuid();
460 ctx->option_daemon = FALSE;
461 ctx->nacl = 0;
462 ctx->pacl = NULL;
463 ctx->option_childsmax = 0;
464 ctx->active_childs = 0;
465 ctx->l2_env = NULL;
466 ctx->l2 = NULL;
467 ctx->saaServerbind = NULL;
468 ctx->saServerbind = NULL;
469 ctx->saaClientbind = NULL;
470 ctx->saClientbind = NULL;
471 ctx->saaIO = NULL;
472 ctx->saIO = NULL;
473 ctx->fdIOi = -1;
474 ctx->fdIOo = -1;
475 ctx->nns = 0;
476 ctx->pns = NULL;
477 ctx->azGroupargs = NULL;
478 ctx->asGroupargs = 0;
479 initsession(&ctx->session);
480 ctx->msg = NULL;
481 ctx->config_varregex = NULL;
482 ctx->config_varctx = NULL;
483 ctx->msgcount = 0;
484
485 /* private application context */
486 if (val_create(&ctx->prival) != VAL_OK)
487 CU(ERR_EXECUTION);
488
489 /* create printable variables context and mount it into the private application context */
490 if (val_create(&ctx->val) != VAL_OK)
491 CU(ERR_EXECUTION);
492 if (val_reg(ctx->prival, "printable", VAL_TYPE_VAL, "printable variables", NULL) != VAL_OK)
493 CU(ERR_EXECUTION);
494 if (val_set(ctx->prival, "printable", ctx->val) != VAL_OK)
495 CU(ERR_EXECUTION);
496
497 /* feed lib_val */
498 if (val_reg(ctx->prival, "msgcount", VAL_TYPE_INT, "number of messages processed so far", (void *)&ctx->msgcount) != VAL_OK)
499 CU(ERR_EXECUTION);
500 if (val_reg(ctx->prival, "nodename", VAL_TYPE_PTR, "nodename configured or uname(3)", (void *)&ctx->option_nodename) != VAL_OK)
501 CU(ERR_EXECUTION);
502
503 /* set progname */
504 ctx->progname = strdup(argv[0]);
505
506 /* establish variable expansion context */
507 {
508 char *cp;
509
510 if ((rc = var_create(&ctx->config_varctx)) != VAR_OK) {
511 fprintf(stderr, "%s:Error: create varctx context failed with %s (%d)", ctx->progname, var_strerror(ctx->config_varctx, rc, &cp) == VAR_OK ? cp : "Unknown Error", rc);
512 CU(ERR_EXECUTION);
513 }
514 if ((rc = var_config(ctx->config_varctx, VAR_CONFIG_SYNTAX, &syntax_ctx)) != VAR_OK) {
515 fprintf(stderr, "%s:Error: config varctx context failed with %s (%d)", ctx->progname, var_strerror(ctx->config_varctx, rc, &cp) == VAR_OK ? cp : "Unknown Error", rc);
516 CU(ERR_EXECUTION);
517 }
518 if ((rc = var_config(ctx->config_varctx, VAR_CONFIG_CB_VALUE, ctx_lookup, ctx)) != VAR_OK) {
519 fprintf(stderr, "%s:Error: config varctx callback failed with %s (%d)", ctx->progname, var_strerror(ctx->config_varctx, rc, &cp) == VAR_OK ? cp : "Unknown Error", rc);
520 CU(ERR_EXECUTION);
521 }
522 }
523
524
525 /* read in the arguments */
526 {
527 lmtp2nntp_option_rc_t rvo;
528 lmtp2nntp_config_rc_t rvc;
529 ex_t ex;
530
531 if (option_create(&o, ctx->val) != OPTION_OK)
532 CU(ERR_EXECUTION);
533 rvo = option_parse(o, argc, argv);
534 rvc = CONFIG_OK;
535 try {
536 rvc = config_context(ctx);
537 }
538 catch(ex) {
539 rvc = CONFIG_ERR_TRY;
540 }
541 if (rvc == CONFIG_OK_DRY)
542 CU(0);
543 if (rvo != OPTION_OK || rvc != CONFIG_OK)
544 CU(ERR_EXECUTION);
545 }
546
547 if (getuid() != ctx->option_uid) {
548 if (setuid(ctx->option_uid) == -1) {
549 fprintf(stderr, "%s:Error: Setting UID to %d failed: %s\n",
550 ctx->progname, (int)ctx->option_uid, strerror(errno));
551 CU(ERR_EXECUTION);
552 }
553 }
554
555 if ((ctx->option_pidfile != NULL) && ctx->option_killflag) {
556 if ((fd = fopen(ctx->option_pidfile, "r")) == NULL)
557 logbook(ctx->l2, L2_LEVEL_ERROR, "cannot open pidfile \"%s\" for reading %m", ctx->option_pidfile);
558 else {
559 if (fscanf(fd, "%d\n", (int *)&pid) != 1) {
560 fclose(fd);
561 logbook(ctx->l2, L2_LEVEL_ERROR, "cannot extract pid from pidfile \"%s\"", ctx->option_pidfile);
562 }
563 else {
564 fclose(fd);
565 logbook(ctx->l2, L2_LEVEL_TRACE, "going to kill pid[%d]", pid);
566 if (kill(pid, SIGHUP) == -1)
567 logbook(ctx->l2, L2_LEVEL_ERROR, "killing pid[%d] failed %m", pid);
568 if (unlink(ctx->option_pidfile) == -1)
569 logbook(ctx->l2, L2_LEVEL_ERROR, "unlinking pidfile \"%s\" failed %m", ctx->option_pidfile);
570 }
571 }
572 CU(0);
573 }
574
575 catchsignal(0, ctx);
576 signal(SIGCHLD, (void(*)())catchsignal);
577 signal(SIGHUP, (void(*)())catchsignal);
578 signal(SIGINT, (void(*)())catchsignal);
579 signal(SIGQUIT, (void(*)())catchsignal);
580 signal(SIGILL, (void(*)())catchsignal);
581 signal(SIGBUS, (void(*)())catchsignal);
582 signal(SIGSEGV, (void(*)())catchsignal);
583 signal(SIGSYS, (void(*)())catchsignal);
584 signal(SIGTERM, (void(*)())catchsignal);
585 signal(SIGUSR1, (void(*)())catchsignal);
586 signal(SIGUSR2, SIG_IGN );
587
588 /* loop for LMTP protocol with support for alternate io through daemon */
589 if (ctx->saServerbind == NULL) {
590 /* initialize LMTP context */
591 ctx->fdIOi = STDIN_FILENO;
592 ctx->fdIOo = STDOUT_FILENO;
593 lmtp_io.ctx = ctx;
594 lmtp_io.read = hook_lmtp_read;
595 lmtp_io.write = hook_lmtp_write;
596 if ((lmtp = lmtp_create(&lmtp_io)) == NULL) {
597 logbook(ctx->l2, L2_LEVEL_ERROR, "Unable to initialize LMTP library\n");
598 CU(ERR_EXECUTION);
599 }
600 /* RFC0821, 4.5.1. MINIMUM IMPLEMENTATION
601 * In order to make SMTP workable, the following minimum implementation
602 * is required for all receivers: [...]
603 * RFC0821, 4.1.2. COMMAND SYNTAX
604 *
605 * Verb Parameter
606 * ----+-------------------------------
607 * HELO <SP> <domain> <CRLF>
608 * MAIL <SP> FROM:<reverse-path> <CRLF>
609 * RCPT <SP> TO:<forward-path> <CRLF>
610 * DATA <CRLF>
611 * RSET <CRLF>
612 * NOOP <CRLF>
613 * QUIT <CRLF>
614 */
615 lmtp_register(lmtp, "LHLO", lmtp_cb_lhlo, ctx, NULL, NULL);
616 lmtp_register(lmtp, "MAIL", lmtp_cb_mail, ctx, NULL, NULL);
617 lmtp_register(lmtp, "RCPT", lmtp_cb_rcpt, ctx, NULL, NULL);
618 lmtp_register(lmtp, "DATA", lmtp_cb_data, ctx, NULL, NULL);
619 lmtp_register(lmtp, "RSET", lmtp_cb_rset, ctx, NULL, NULL);
620 lmtp_register(lmtp, "NOOP", lmtp_cb_noop, ctx, NULL, NULL);
621 lmtp_register(lmtp, "QUIT", lmtp_cb_quit, ctx, NULL, NULL);
622 lmtp_loop(lmtp);
623 lmtp_gfs_quit(ctx);
624 lmtp_gfs_lhlo(ctx);
625 lmtp_destroy(lmtp);
626 } else {
627 pid = getpid();
628 if (ctx->option_daemon) {
629 daemonize();
630 logbook(ctx->l2, L2_LEVEL_NOTICE, "daemonized, previous pid[%d]", pid);
631 }
632 if (ctx->option_pidfile != NULL) {
633 if ((fd = fopen(ctx->option_pidfile, "w+")) == NULL)
634 logbook(ctx->l2, L2_LEVEL_ERROR, "cannot open pidfile \"%s\" for writing %m", ctx->option_pidfile);
635 else {
636 fprintf(fd, "%d\n", (int)getpid());
637 fclose(fd);
638 }
639 }
640
641 sa_timeout(ctx->saServerbind, SA_TIMEOUT_ALL, 0, 0);
642 sa_timeout(ctx->saServerbind, SA_TIMEOUT_ACCEPT, ctx->option_timeout_lmtp_accept, 0);
643 sa_timeout(ctx->saServerbind, SA_TIMEOUT_READ, ctx->option_timeout_lmtp_read, 0);
644 sa_timeout(ctx->saServerbind, SA_TIMEOUT_WRITE, ctx->option_timeout_lmtp_write, 0);
645 while (1) {
646 while (ctx->active_childs >= ctx->option_childsmax) {
647 logbook(ctx->l2, L2_LEVEL_ERROR, "maximum number of childs (%d) reached - waiting (1s)", ctx->option_childsmax);
648 sleep(1);
649 }
650
651 if ((rc = sa_accept(ctx->saServerbind, &ctx->saaIO, &ctx->saIO)) != SA_OK) {
652 if (rc == SA_ERR_SYS)
653 logbook(ctx->l2, L2_LEVEL_ERROR, "accept failed: %s: (%d) %s", sa_error(rc), errno, strerror(errno));
654 else
655 logbook(ctx->l2, L2_LEVEL_ERROR, "accept failed: %s", sa_error(rc));
656 sleep(10);
657 continue;
658 }
659
660 /* Access Control List */
661 bOk = FALSE;
662 /* check positive matches */
663 for (i = 0; i < ctx->nacl; i++) {
664 char *cpA1;
665 char *cpA2;
666 if (ctx->pacl[i].not)
667 continue;
668 sa_addr_a2u(ctx->pacl[i].saa, &cpA1);
669 sa_addr_a2u(ctx->saaIO, &cpA2);
670 if (sa_addr_match(ctx->saaIO, ctx->pacl[i].saa, ctx->pacl[i].prefixlen) == SA_OK) {
671 logbook(ctx->l2, L2_LEVEL_TRACE, "positive/inclusive ACL \"%s\" (%s/%d) matches %s: YES (stop comparison)", ctx->pacl[i].acl, cpA1, ctx->pacl[i].prefixlen, cpA2);
672 bOk = TRUE;
673 break;
674 }
675 else
676 logbook(ctx->l2, L2_LEVEL_TRACE, "positive/inclusive ACL \"%s\" (%s/%d) matches %s: NO", ctx->pacl[i].acl, cpA1, ctx->pacl[i].prefixlen, cpA2);
677 free(cpA1);
678 free(cpA2);
679 }
680 /* check negative matches */
681 for (i = 0; i < ctx->nacl; i++) {
682 char *cpA1;
683 char *cpA2;
684 if (!ctx->pacl[i].not)
685 continue;
686 sa_addr_a2u(ctx->pacl[i].saa, &cpA1);
687 sa_addr_a2u(ctx->saaIO, &cpA2);
688 if (sa_addr_match(ctx->saaIO, ctx->pacl[i].saa, ctx->pacl[i].prefixlen) == SA_OK) {
689 logbook(ctx->l2, L2_LEVEL_TRACE, "negative/exclusive ACL \"%s\" (not %s/%d) matches %s: YES (stop comparison)", ctx->pacl[i].acl, cpA1, ctx->pacl[i].prefixlen, cpA2);
690 bOk = FALSE;
691 break;
692 }
693 else {
694 logbook(ctx->l2, L2_LEVEL_TRACE, "negative/exclusive ACL \"%s\" (not %s/%d) matches %s: NO", ctx->pacl[i].acl, cpA1, ctx->pacl[i].prefixlen, cpA2);
695 }
696 }
697 if (bOk) {
698 char *cpA;
699 sa_addr_a2u(ctx->saaIO, &cpA);
700 logbook(ctx->l2, L2_LEVEL_TRACE, "connection from %s accepted due to ACL", cpA);
701 free(cpA);
702 }
703 else {
704 char *cpA;
705 sa_addr_a2u(ctx->saaIO, &cpA);
706 logbook(ctx->l2, L2_LEVEL_ERROR, "connection from %s refused due to ACL", cpA);
707 free(cpA);
708 sa_destroy(ctx->saIO);
709 sa_addr_destroy(ctx->saaIO);
710 continue;
711 }
712
713 /* logging buffer must be empty before fork otherwise content is
714 * duplicated and written twice on next flush */
715 l2_channel_flush(ctx->l2);
716 pid = fork();
717 if (pid == -1) {
718 logbook(ctx->l2, L2_LEVEL_ERROR, "daemon cannot spawn child %m");
719 continue;
720 }
721 if (pid != 0) {
722 logbook(ctx->l2, L2_LEVEL_INFO, "daemon forked process, new child pid[%d]", pid);
723 ctx->active_childs++;
724 sa_destroy(ctx->saIO);
725 sa_addr_destroy(ctx->saaIO);
726 continue;
727 }
728 logbook(ctx->l2, L2_LEVEL_NOTICE, "startup new child process, parent pid[%d]", getppid());
729
730 /* child must close listening socket */
731 sa_destroy(ctx->saServerbind);
732 ctx->saServerbind = NULL; /* prevent cleanup from free'ing this again */
733
734 /* initialize LMTP context */
735 lmtp_io.ctx = ctx;
736 lmtp_io.read = hook_lmtp_read;
737 lmtp_io.write = hook_lmtp_write;
738 if ((lmtp = lmtp_create(&lmtp_io)) == NULL) {
739 logbook(ctx->l2, L2_LEVEL_ERROR, "Unable to initialize LMTP library\n");
740 CU(ERR_EXECUTION);
741 }
742 /* RFC0821, 4.5.1. MINIMUM IMPLEMENTATION
743 * In order to make SMTP workable, the following minimum implementation
744 * is required for all receivers: [...]
745 * RFC0821, 4.1.2. COMMAND SYNTAX
746 *
747 * Verb Parameter
748 * ----+-------------------------------
749 * HELO <SP> <domain> <CRLF>
750 * MAIL <SP> FROM:<reverse-path> <CRLF>
751 * RCPT <SP> TO:<forward-path> <CRLF>
752 * DATA <CRLF>
753 * RSET <CRLF>
754 * NOOP <CRLF>
755 * QUIT <CRLF>
756 */
757 lmtp_register(lmtp, "LHLO", lmtp_cb_lhlo, ctx, NULL, NULL);
758 lmtp_register(lmtp, "MAIL", lmtp_cb_mail, ctx, NULL, NULL);
759 lmtp_register(lmtp, "RCPT", lmtp_cb_rcpt, ctx, NULL, NULL);
760 lmtp_register(lmtp, "DATA", lmtp_cb_data, ctx, NULL, NULL);
761 lmtp_register(lmtp, "RSET", lmtp_cb_rset, ctx, NULL, NULL);
762 lmtp_register(lmtp, "NOOP", lmtp_cb_noop, ctx, NULL, NULL);
763 lmtp_register(lmtp, "QUIT", lmtp_cb_quit, ctx, NULL, NULL);
764 lmtp_loop(lmtp);
765 lmtp_gfs_quit(ctx);
766 lmtp_gfs_lhlo(ctx);
767 lmtp_destroy(lmtp);
768 CU(0);
769 }
770 }
771 CU(0);
772
773 /* graceful shutdown */
774 CUS:
775 signal(SIGCHLD, SIG_DFL);
776 signal(SIGHUP, SIG_DFL);
777 signal(SIGINT, SIG_DFL);
778 signal(SIGQUIT, SIG_DFL);
779 signal(SIGILL, SIG_DFL);
780 signal(SIGBUS, SIG_DFL);
781 signal(SIGSEGV, SIG_DFL);
782 signal(SIGSYS, SIG_DFL);
783 signal(SIGTERM, SIG_DFL);
784 signal(SIGUSR1, SIG_DFL);
785 signal(SIGUSR2, SIG_DFL);
786 logbook(ctx->l2, L2_LEVEL_NOTICE, "graceful shutdown shortly before exit - no more logging");
787 if (ctx->l2 != NULL)
788 l2_channel_destroy(ctx->l2);
789 if (ctx->l2_env != NULL)
790 l2_env_destroy(ctx->l2_env);
791 if (ctx->saServerbind)
792 sa_destroy(ctx->saServerbind);
793 if (ctx->saaServerbind)
794 sa_addr_destroy(ctx->saaServerbind);
795 if (ctx->option_restrictheader != NULL)
796 free(ctx->option_restrictheader);
797 if (ctx->option_pidfile != NULL)
798 free(ctx->option_pidfile);
799 if (ctx->pns != NULL)
800 free(ctx->pns);
801 if (ctx->pacl != NULL) {
802 for (i = 0; i < ctx->nacl; i++)
803 if (ctx->pacl[i].saa != NULL)
804 sa_addr_destroy(ctx->pacl[i].saa);
805 free(ctx->pacl);
806 }
807 if (ctx->option_nodename != NULL)
808 free(ctx->option_nodename);
809 if (ctx->prival != NULL)
810 val_destroy(ctx->prival);
811 if (ctx->val != NULL)
812 val_destroy(ctx->val);
813 if (ctx->progname != NULL)
814 free(ctx->progname);
815 if (ctx->azGroupargs != NULL)
816 free(ctx->azGroupargs);
817 if (ctx->config_varregex != NULL)
818 var_destroy(ctx->config_varregex);
819 if (ctx->config_varctx != NULL)
820 var_destroy(ctx->config_varctx);
821 if (ctx->option_operationmodefakestatus != NULL)
822 free(ctx->option_operationmodefakestatus); /* includes dsn */
823 if (ctx != NULL)
824 free(ctx);
825 str_parse(NULL, NULL);
826 if (o != NULL)
827 (void)option_destroy(o);
828 return rc;
829 }
830
resetsession(struct session * session)831 static void resetsession(struct session *session)
832 {
833 if (session->lhlo_domain != NULL)
834 free(session->lhlo_domain);
835 initsession(session);
836 return;
837 }
838
initsession(struct session * session)839 static void initsession(struct session *session)
840 {
841 session->lhlo_seen = FALSE;
842 session->lhlo_domain = NULL;
843 return;
844 }
845
lmtp_cb_lhlo(lmtp_t * lmtp,lmtp_io_t * io,lmtp_req_t * req,void * _ctx)846 static lmtp_rc_t lmtp_cb_lhlo(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
847 {
848 /*
849 * RFC0821 [excerpt] 4.1. SMTP COMMANDS
850 * 4.1.1. COMMAND SEMANTICS, HELO
851 * This command and an OK reply to it confirm that both the sender-SMTP
852 * and the receiver-SMTP are in the initial state, that is, there is no
853 * transaction in progress and all state tables and buffers are cleared.
854 *
855 * The first command in a session must be the HELO command. The HELO
856 * command may be used later in a session as well. If the HELO command
857 * argument is not acceptable a 501 failure reply must be returned and
858 * the receiver-SMTP must stay in the same state.
859 *
860 * If the transaction beginning command argument is not acceptable a 501
861 * failure reply must be returned and the receiver-SMTP must stay in the
862 * same state. If the commands in a transaction are out of order a 503
863 * failure reply must be returned and the receiver-SMTP must stay in the
864 * same state.
865 *
866 * HELO <SP> <domain> <CRLF>
867 */
868 lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
869 nntp_rc_t rc;
870 lmtp_res_t res;
871 char str[STDSTRLEN];
872 int bOk;
873 int i;
874 int is;
875 nntp_io_t nntp_io;
876
877 logbook(ctx->l2, L2_LEVEL_INFO, "LMTP service executing LHLO command < %s", req->msg);
878
879 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 503 Bad sequence of commands
880 * RFC1893 2. Status Codes 5.X.X Permanent Failure
881 * RFC1893 3.5 Network and Routing Status X.0.0 Other undefined Status
882 */
883 logbook(ctx->l2, L2_LEVEL_TRACE, "checking for duplicate LHLO");
884 if (ctx->session.lhlo_seen) {
885 res.statuscode = "503";
886 res.dsncode = "5.0.0";
887 res.statusmsg = "Duplicate LHLO.";
888 CU(LMTP_OK);
889 }
890
891 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 501 Syntax error in parameters or arguments
892 * RFC1893 2. Status Codes 5.X.X Permanent Failure
893 * RFC1893 3.5 Network and Routing Status X.0.0 Other undefined Status
894 */
895 logbook(ctx->l2, L2_LEVEL_TRACE, "checking domain to match either RFC0821 or RFC1035 syntax");
896 if (! ( helo_rfc0821domain(req->msg, &ctx->session.lhlo_domain) > 0
897 || helo_rfc1035domain(req->msg, &ctx->session.lhlo_domain) > 0)) {
898 res.statuscode = "501";
899 res.dsncode = "5.0.0";
900 res.statusmsg = "Please identify yourself. Domain must match RFC0821/RFC1035.";
901 CU(LMTP_OK);
902 }
903
904 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 451 Requested action aborted: local error in processing
905 * RFC1893 2. Status Codes 4.X.X Persistent Transient Failure
906 * RFC1893 3.5 Network and Routing Status X.3.5 System incorrectly configured
907 */
908 if (ctx->option_operationmode != OPERATIONMODE_FAKE) {
909 logbook(ctx->l2, L2_LEVEL_TRACE, "check if at least one NNTP service was successfully configured");
910 if (ctx->nns == 0) {
911 res.statuscode = "451";
912 res.dsncode = "4.3.5";
913 res.statusmsg = "No valid NNTP services configured.";
914 CU(LMTP_OK);
915 }
916 }
917
918 logbook(ctx->l2, L2_LEVEL_TRACE, "try to establish a session to any configured NNTP services");
919 if (ctx->option_operationmode == OPERATIONMODE_FAKE)
920 logbook(ctx->l2, L2_LEVEL_NOTICE, "NNTP running in fake mode, network connections will be executed but result is ignored");
921 i = 0;
922 is = 0;
923 while (i < ctx->nns) {
924 logbook(ctx->l2, L2_LEVEL_DEBUG, "trying ns[%d]", i);
925 bOk = TRUE;
926 logbook(ctx->l2, L2_LEVEL_TRACE, "try destination#%d ${option.destination[%d]}", i, i);
927
928 ctx->pns[i].l2 = ctx->l2;
929
930 if (bOk && (ctx->saaClientbind != NULL)) {
931 logbook(ctx->l2, L2_LEVEL_DEBUG, "bind local socket to ${option.client}");
932 if (sa_bind(ctx->pns[i].sa, ctx->saaClientbind) != SA_OK) {
933 bOk = FALSE;
934 logbook(ctx->l2, L2_LEVEL_ERROR, "binding NNTP client to local address ${option.client} failed, %m");
935 }
936 }
937
938 sa_timeout(ctx->pns[i].sa, SA_TIMEOUT_ALL, 0, 0);
939 sa_timeout(ctx->pns[i].sa, SA_TIMEOUT_CONNECT, ctx->option_timeout_nntp_connect, 0);
940 sa_timeout(ctx->pns[i].sa, SA_TIMEOUT_READ, ctx->option_timeout_nntp_read, 0);
941 sa_timeout(ctx->pns[i].sa, SA_TIMEOUT_WRITE, ctx->option_timeout_nntp_read, 0);
942
943 if (bOk) {
944 logbook(ctx->l2, L2_LEVEL_DEBUG, "connect");
945 if (sa_connect(ctx->pns[i].sa, ctx->pns[i].saa) != SA_OK) {
946 bOk = FALSE;
947 logbook(ctx->l2, L2_LEVEL_WARNING, "connect to destination#%d ${option.destination[%d]} failed, %m", i, i);
948 }
949 }
950
951 if (bOk) {
952 logbook(ctx->l2, L2_LEVEL_DEBUG, "nntp_create");
953 nntp_io.ctx = &ctx->pns[i];
954 nntp_io.read = hook_nntp_read;
955 nntp_io.write = hook_nntp_write;
956 if ((ctx->pns[i].nntp = nntp_create(&nntp_io)) == NULL) {
957 bOk = FALSE;
958 logbook(ctx->l2, L2_LEVEL_ERROR, "creation of NNTP context failed");
959 }
960 }
961
962 if (bOk) {
963 logbook(ctx->l2, L2_LEVEL_DEBUG, "nntp_init");
964 if ((rc = nntp_init(ctx->pns[i].nntp)) != NNTP_OK) {
965 bOk = FALSE;
966 logbook(ctx->l2, L2_LEVEL_ERROR, "initialization of NNTP context failed, (%d) %s", rc, nntp_error(rc));
967 }
968 }
969
970 if (bOk) {
971 logbook(ctx->l2, L2_LEVEL_INFO, "NNTP session to destination#%d ${option.destination[%d]} successfully established", i, i);
972 is++;
973 }
974 else {
975 logbook(ctx->l2, L2_LEVEL_WARNING, "NNTP session establishment to destination#%d ${option.destination[%d]} failed", i, i);
976 lmtp_gfs_ns(&ctx->pns[i]);
977 }
978 i++;
979 }
980 logbook(ctx->l2, L2_LEVEL_INFO, "NNTP network connections tried %d, successful %d", i, is);
981
982 if (ctx->option_operationmode == OPERATIONMODE_FAKE)
983 logbook(ctx->l2, L2_LEVEL_NOTICE, "NNTP running in fake mode, ignoring status of real network connections");
984 else
985 {
986 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 421 <domain> Service not available
987 * RFC1893 2. Status Codes 4.X.X Persistent Transient Failure
988 * RFC1893 3.5 Network and Routing Status X.4.1 No answer from host
989 */
990 logbook(ctx->l2, L2_LEVEL_DEBUG, "check if at least one NNTP session successfully established");
991 if (is == 0) {
992 logbook(ctx->l2, L2_LEVEL_ERROR, "no NNTP session established");
993 res.statuscode = "421";
994 res.dsncode = "4.4.1";
995 res.statusmsg = "No NNTP session established.";
996 CU(LMTP_OK);
997 }
998 }
999
1000 ctx->session.lhlo_seen = TRUE;
1001
1002 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 250 Requested mail action okay, completed
1003 */
1004 str_format(str, sizeof(str),
1005 "%s Hello %s, pleased to meet you.\n" /* RFC2821 4.1.1.1 */
1006 "ENHANCEDSTATUSCODES\n" /* RFC2034 */
1007 "DSN\n" /* RFC1894 */
1008 "PIPELINING\n" /* RFC1854 */
1009 "8BITMIME", /* RFC1652 */
1010 ctx->option_nodename,
1011 ctx->session.lhlo_domain);
1012 res.statuscode = "250";
1013 res.dsncode = NULL; /* DSN not used for greeting */
1014 res.statusmsg = str;
1015 CU(LMTP_OK);
1016
1017 CUS:
1018 lmtp_response(lmtp, &res);
1019 return rc;
1020 }
1021
lmtp_gfs_ns(struct ns * ns)1022 static void lmtp_gfs_ns(struct ns *ns)
1023 {
1024 if (ns->nntp != NULL) {
1025 nntp_destroy(ns->nntp);
1026 ns->nntp = NULL;
1027 }
1028 if (ns->sa != NULL) {
1029 sa_destroy(ns->sa);
1030 ns->sa = NULL;
1031 }
1032 if (ns->saa != NULL) {
1033 sa_addr_destroy(ns->saa);
1034 ns->saa = NULL;
1035 }
1036 }
1037
lmtp_gfs_lhlo(lmtp2nntp_t * ctx)1038 static void lmtp_gfs_lhlo(lmtp2nntp_t *ctx)
1039 {
1040 int i;
1041
1042 logbook(ctx->l2, L2_LEVEL_TRACE, "LMTP service LHLO command - graceful shutdown");
1043
1044 for (i = 0; i < ctx->nns; i++)
1045 lmtp_gfs_ns(&ctx->pns[i]);
1046
1047 if (ctx->option_mailfrom != NULL)
1048 free(ctx->option_mailfrom);
1049 if (ctx->saClientbind != NULL)
1050 sa_destroy(ctx->saClientbind);
1051 if (ctx->saaClientbind != NULL)
1052 sa_addr_destroy(ctx->saaClientbind);
1053 }
1054
helo_rfc0821domain(char * msg,char ** domain)1055 static int helo_rfc0821domain(char *msg, char **domain)
1056 {
1057 int rc;
1058
1059 rc = str_parse(msg,
1060 "^.+ ("
1061 /*
1062 ##
1063 ## The mega Perl regular expression below is generated
1064 ## with the following Perl program. This is only possible
1065 ## because the given grammar is Chomsky-3 (right or left
1066 ## linear grammar, but noth both).
1067 ##
1068
1069 # BNF grammar for <domain> according to RFC0821:
1070 # <snum> ::= one, two, or three digits representing a decimal integer value in the range 0 through 255
1071 # <a> ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case
1072 # <d> ::= any one of the ten digits 0 through 9
1073 # <let-dig-hyp> ::= <a> | <d> | "-"
1074 # <let-dig> ::= <a> | <d>
1075 # <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
1076 # <dotnum> ::= <snum> "." <snum> "." <snum> "." <snum>
1077 # <number> ::= <d> | <d> <number>
1078 # <name> ::= <a> <ldh-str> <let-dig>
1079 # <element> ::= <name> | "#" <number> | "[" <dotnum> "]"
1080 # <domain> ::= <element> | <element> "." <domain>
1081 #
1082 # corresponding Perl regular expression ($domain)
1083 $snum = "(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])";
1084 $d = "[0-9]";
1085 $a = "[A-Za-z]";
1086 $let_dig_hyp = "(?:$a|$d|-)";
1087 $let_dig = "(?:$a|$d)";
1088 $ldh_str = "${let_dig_hyp}+";
1089 $dotnum = "$snum\\.$snum\\.$snum\\.$snum";
1090 $number = "$d+";
1091 $name = "$a$ldh_str$let_dig";
1092 $element = "(?:$name|#$number|\\[$dotnum\\])";
1093 $domain = "(?:$element\.)*$element";
1094 #
1095 # translate into C string block suitable for passing to the Perl
1096 # Compatible Regular Expressions (PCRE) based string library Str.
1097 my $cregex = $domain;
1098 $cregex .= "\n";
1099 $cregex =~ s|\\|\\\\|sg;
1100 $cregex =~ s|(.{17})|$1\n|sg;
1101 $cregex =~ s|([^\n]+)\n|"$1"\n|sg;
1102 $cregex =~ s|\n\n|\n|sg;
1103 print "$cregex";
1104 */
1105
1106 "(?:(?:[A-Za-z](?:[A-Za-z]|[0-9]|-)+(?:[A-Za-z]|[0-9])|#[0-9]+|\\[(?:[0"
1107 "-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0"
1108 "-1][0-9]{2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0"
1109 "-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5"
1110 "])\\]).)*(?:[A-Za-z](?:[A-Za-z]|[0-9]|-)+(?:[A-Za-z]|[0-9])|#[0-9]+|\\"
1111 "[(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]"
1112 "{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0-1][0-9]{"
1113 "2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|"
1114 "25[0-5])\\])"
1115
1116 ")$", domain);
1117 return rc;
1118 }
1119
helo_rfc1035domain(char * msg,char ** domain)1120 static int helo_rfc1035domain(char *msg, char **domain)
1121 {
1122 int rc;
1123
1124 rc = str_parse(msg,
1125 "^.+ ("
1126 /*
1127 ##
1128 ## The mega Perl regular expression below is generated
1129 ## with the following Perl program. This is only possible
1130 ## because the given grammar is Chomsky-3 (right or left
1131 ## linear grammar, but noth both).
1132 ##
1133
1134 # BNF grammar for <domain> according to RFC1035:
1135 # <letter> ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case
1136 # <digit> ::= any one of the ten digits 0 through 9
1137 # <let-dig> ::= <letter> | <digit>
1138 # <let-dig-hyp> ::= <let-dig> | "-"
1139 # <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
1140 # <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
1141 # <subdomain> ::= <label> | <subdomain> "." <label>
1142 # <domain> ::= <subdomain> | " "
1143 #
1144 # corresponding Perl regular expression ($domain)
1145 $letter = "[A-Za-z]";
1146 $digit = "[0-9]";
1147 $let_dig = "(?:$letter|$digit)";
1148 $let_dig_hyp = "(?:$let_dig|-)";
1149 $ldh_str = "${let_dig_hyp}+";
1150 $label = "(?:$letter(?:(?:$ldh_str)?$let_dig)?)";
1151 $subdomain = "(?:$label\.)*$label";
1152 $domain = "(?:$subdomain| )";
1153 #
1154 # translate into C string block suitable for passing to the Perl
1155 # Compatible Regular Expressions (PCRE) based string library Str.
1156 my $cregex = $domain;
1157 $cregex .= "\n";
1158 $cregex =~ s|\\|\\\\|sg;
1159 $cregex =~ s|(.{17})|$1\n|sg;
1160 $cregex =~ s|([^\n]+)\n|"$1"\n|sg;
1161 $cregex =~ s|\n\n|\n|sg;
1162 print "$cregex";
1163 */
1164
1165 "(?:(?:(?:[A-Za-z](?:(?:(?:(?:[A-Za-z]|[0-9])|-)+)?(?:[A-Za-z]|[0-9]))?"
1166 ").)*(?:[A-Za-z](?:(?:(?:(?:[A-Za-z]|[0-9])|-)+)?(?:[A-Za-z]|[0-9]))?)|"
1167 " )"
1168
1169 ")$", domain);
1170 return rc;
1171 }
1172
lmtp_cb_mail(lmtp_t * lmtp,lmtp_io_t * io,lmtp_req_t * req,void * _ctx)1173 static lmtp_rc_t lmtp_cb_mail(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
1174 {
1175 lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
1176 lmtp_rc_t rc;
1177 lmtp_res_t res;
1178
1179 logbook(ctx->l2, L2_LEVEL_INFO, "LMTP service executing MAIL command < %s", req->msg);
1180
1181 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 553 Requested action not taken: mailbox name not allowed
1182 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1183 * RFC1893 3.5 Network and Routing Status X.1.8 Bad sender's system address
1184 */
1185 logbook(ctx->l2, L2_LEVEL_TRACE, "checking for previous LHLO");
1186 if (!ctx->session.lhlo_seen) {
1187 res.statuscode = "553";
1188 res.dsncode = "5.1.8";
1189 res.statusmsg = "friendly people say LHLO to open a transmission channel.";
1190 CU(LMTP_OK);
1191 }
1192
1193 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 503 Bad sequence of commands
1194 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1195 * RFC1893 3.5 Network and Routing Status X.5.0 Other or undefined protocol status
1196 */
1197 logbook(ctx->l2, L2_LEVEL_TRACE, "checking for previous MAIL");
1198 if (ctx->msg != NULL) {
1199 res.statuscode = "503";
1200 res.dsncode = "5.5.0";
1201 res.statusmsg = "Sender already specified.";
1202 CU(LMTP_OK);
1203 }
1204
1205 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 452 Requested action not taken: insufficient system storage
1206 * RFC1893 2. Status Codes 4.X.X Persistent Transient Failure
1207 * RFC1893 3.5 Network and Routing Status X.3.1 Mail system full
1208 */
1209 logbook(ctx->l2, L2_LEVEL_TRACE, "msg_create");
1210 ctx->msgcount++;
1211 if ((ctx->msg = msg_create(ctx->prival)) == NULL) {
1212 res.statuscode = "452";
1213 res.dsncode = "4.3.1";
1214 res.statusmsg = "Internal error - memory.";
1215 CU(LMTP_ERR_MEM);
1216 }
1217 ctx->msg->l2 = ctx->l2;
1218
1219 /* RFC1652 2. Framework for the 8bit MIME Transport Extension
1220 * (4) one optional parameter using the keyword BODY is added to the MAIL
1221 * FROM command. The value associated with this parameter is a keyword
1222 * indicating whether a 7bit message [...] or a MIME message [...] is
1223 * being sent. The syntax of the value is as follows, using the ABNF
1224 * notation [...]
1225 *
1226 * body-value ::= "7BIT" / "8BITMIME"
1227 *
1228 * "MAIL From:<foo@bar>"
1229 * "MAIL From:<foo@bar> BODY=8BITMIME"
1230 * "MAIL From:<foo@bar> BODY=7BIT"
1231 *
1232 * RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 553 Requested action not taken: mailbox name not allowed
1233 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1234 * RFC1893 3.5 Network and Routing Status X.1.7 Bad sender's mailbox address syntax
1235 */
1236 logbook(ctx->l2, L2_LEVEL_TRACE, "checking if sender address is a domain name");
1237 if (str_parse(req->msg, "m/^MAIL From:\\s*<(?:.+@.+)>/i") <= 0) {
1238 res.statuscode = "553";
1239 res.dsncode = "5.1.7";
1240 res.statusmsg = "Domain name required for sender address.";
1241 CU(LMTP_OK);
1242 }
1243 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 501 Syntax error in parameters or arguments
1244 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1245 * RFC1893 3.5 Network and Routing Status X.5.4 Invalid command arguments
1246 */
1247 logbook(ctx->l2, L2_LEVEL_TRACE, "checking BODY keyword");
1248 if (str_parse(req->msg, "m/^MAIL From:\\s*<(.+@.+)>"
1249 "(?:\\s+BODY=(?:7BIT|8BITMIME)\\s*)?$/i",
1250 &ctx->msg->mail_from) <= 0) {
1251 res.statuscode = "501";
1252 res.dsncode = "5.5.4";
1253 res.statusmsg = "Unknown parameter for keyword BODY.";
1254 CU(LMTP_OK);
1255 }
1256
1257 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 550 Requested action not taken: mailbox unavailable
1258 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1259 * RFC1893 3.5 Network and Routing Status X.7.1 Delivery not authorized, message refused
1260 */
1261 logbook(ctx->l2, L2_LEVEL_TRACE, "checking if sender is allowed");
1262 if (ctx->option_mailfrom != NULL) {
1263 logbook(ctx->l2, L2_LEVEL_TRACE, "\"%s\" matching against \"%s\"", ctx->msg->mail_from, ctx->option_mailfrom);
1264 if (str_parse(ctx->msg->mail_from, ctx->option_mailfrom) <= 0) {
1265 res.statuscode = "550";
1266 res.dsncode = "5.7.1";
1267 res.statusmsg = "Delivery not authorized, message refused.";
1268 CU(LMTP_OK);
1269 }
1270 }
1271
1272 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 250 Requested mail action okay, completed
1273 * RFC1893 2. Status Codes 2.X.X Success
1274 * RFC1893 3.5 Network and Routing Status X.1.0 Other address status
1275 */
1276 res.statuscode = "250";
1277 res.dsncode = "2.1.0";
1278 res.statusmsg = "Sender ok.";
1279 lmtp_response(lmtp, &res);
1280 return LMTP_OK;
1281
1282 CUS:
1283 lmtp_response(lmtp, &res);
1284 if (ctx->msg != NULL) {
1285 msg_destroy(ctx->msg);
1286 ctx->msg = NULL;
1287 }
1288 return rc;
1289 }
1290
lmtp_cb_rcpt(lmtp_t * lmtp,lmtp_io_t * io,lmtp_req_t * req,void * _ctx)1291 static lmtp_rc_t lmtp_cb_rcpt(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
1292 {
1293 lmtp_res_t res;
1294 lmtp_rc_t rc;
1295 lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
1296 char *cp = NULL;
1297 char *group;
1298
1299 logbook(ctx->l2, L2_LEVEL_INFO, "LMTP service executing RCPT command < %s", req->msg);
1300
1301 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 503 Bad sequence of commands
1302 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1303 * RFC1893 3.5 Network and Routing Status X.5.0 Other or undefined protocol status
1304 */
1305 logbook(ctx->l2, L2_LEVEL_TRACE, "checking for previous MAIL");
1306 if ((ctx->msg == NULL) || (ctx->msg->mail_from == NULL)) {
1307 res.statuscode = "503";
1308 res.dsncode = "5.5.0";
1309 res.statusmsg = "specify sender with MAIL first.";
1310 CU(LMTP_OK);
1311 }
1312
1313 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 501 Syntax error in parameters or arguments
1314 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1315 * RFC1893 3.5 Network and Routing Status X.5.2 Syntax error
1316 */
1317 logbook(ctx->l2, L2_LEVEL_TRACE, "checking parameter syntax");
1318 if (str_parse(req->msg, "m/^RCPT To:\\s*(.+)$/i", &cp) <= 0) {
1319 res.statuscode = "501";
1320 res.dsncode = "5.5.2";
1321 res.statusmsg = "Syntax error in parameters.";
1322 CU(LMTP_OK);
1323 }
1324
1325 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 550 Requested action not taken: mailbox unavailable
1326 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1327 * RFC1893 3.5 Network and Routing Status X.1.1 Bad destination mailbox address
1328 */
1329 logbook(ctx->l2, L2_LEVEL_TRACE, "checking for empty parameter");
1330 if ((cp == NULL) || (strlen(cp) == 0)) {
1331 res.statuscode = "550";
1332 res.dsncode = "5.1.1";
1333 res.statusmsg = "empty Recipient/ Group.";
1334 CU(LMTP_OK);
1335 }
1336
1337 /* in GROUPMODE = ARG|HEADER recipient must be acknowledged and stored to
1338 * give proper pipelining responses. in GROUPMODE = ENVELOPE recipient is
1339 * transformed into a group and matched against groupfilter. Only valid
1340 * groups are stored to give proper pipelining responses.
1341 *
1342 * RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 550 Requested action not taken: mailbox unavailable
1343 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1344 * RFC1893 3.5 Network and Routing Status X.1.1 Bad destination mailbox address
1345 * X.7.2 Mailing list expansion prohibited
1346 */
1347 logbook(ctx->l2, L2_LEVEL_DEBUG, "ctx->option_groupmode=%d", ctx->option_groupmode);
1348 if (ctx->option_groupmode == GROUPMODE_ENVELOPE) {
1349 logbook(ctx->l2, L2_LEVEL_TRACE, "groupmode=envelope; transform recipient into group");
1350 if (str_parse(cp, "m/^<(.+)?@[^@]+>$/i", &group) <= 0) {
1351 res.statuscode = "550";
1352 res.dsncode = "5.1.1";
1353 res.statusmsg = "Recipient did not transform into group.";
1354 CU(LMTP_OK);
1355 }
1356 logbook(ctx->l2, L2_LEVEL_TRACE, "groupmode=envelope; match group %s", group);
1357 if (!groupmatch(ctx->azGroupargs, ctx->asGroupargs, group)) {
1358 res.statuscode = "550";
1359 res.dsncode = "5.7.2";
1360 res.statusmsg = "unmatched Group.";
1361 CU(LMTP_OK);
1362 }
1363 logbook(ctx->l2, L2_LEVEL_TRACE, "memorize group %s", group);
1364 argz_add(&ctx->msg->azEnvgroups, &ctx->msg->asEnvgroups, group);
1365 }
1366 logbook(ctx->l2, L2_LEVEL_TRACE, "memorize recipient %s", cp);
1367 argz_add(&ctx->msg->azRcpt, &ctx->msg->asRcpt, cp);
1368
1369 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 250 Requested mail action okay, completed
1370 * RFC1893 2. Status Codes 2.X.X Success
1371 * RFC1893 3.5 Network and Routing Status X.1.5 Destination address valid
1372 */
1373 res.statuscode = "250";
1374 res.dsncode = "2.1.5";
1375 res.statusmsg = ctx->option_groupmode == GROUPMODE_ENVELOPE ? "Group accepted." : "Recipient accepted.";
1376 CU(LMTP_OK);
1377
1378 CUS:
1379 if (cp != NULL)
1380 free(cp);
1381 lmtp_response(lmtp, &res);
1382 return rc;
1383 }
1384
groupmatch(char * azPattern,size_t asPattern,char * cpGroup)1385 int groupmatch(char *azPattern, size_t asPattern, char *cpGroup)
1386 {
1387 int bGroupmatch;
1388 char *cpGroupmatch;
1389
1390 bGroupmatch = FALSE;
1391 cpGroupmatch = NULL;
1392 while ((cpGroupmatch = argz_next(azPattern, asPattern, cpGroupmatch)) != NULL) {
1393 if (shpat_match(cpGroupmatch, cpGroup, 0) == 0)
1394 bGroupmatch = TRUE;
1395 }
1396 return bGroupmatch;
1397 }
1398
lmtp_cb_data(lmtp_t * lmtp,lmtp_io_t * io,lmtp_req_t * req,void * _ctx)1399 static lmtp_rc_t lmtp_cb_data(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
1400 {
1401 lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
1402 lmtp_rc_t rc = LMTP_OK;
1403 lmtp_res_t res;
1404 char *azErr;
1405 size_t asErr;
1406 char errorstring[STDSTRLEN];
1407 char *rcpt;
1408 int i;
1409 int bSuccess;
1410 char *cp;
1411 int bOk;
1412 char *cpRestrictheader;
1413 char *cpRestrictvalue;
1414
1415 logbook(ctx->l2, L2_LEVEL_INFO, "LMTP service executing DATA command < %s", req->msg);
1416
1417 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 503 Bad sequence of commands
1418 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1419 * RFC1893 3.5 Network and Routing Status X.5.0 Other or undefined protocol status
1420 */
1421 logbook(ctx->l2, L2_LEVEL_TRACE, "checking for previous RCPT");
1422 if ((ctx->msg == NULL) || (argz_count(ctx->msg->azRcpt, ctx->msg->asRcpt) == 0)) {
1423 res.statuscode = "503";
1424 res.dsncode = "5.5.0";
1425 res.statusmsg = "specify recipient with RCPT first.";
1426 lmtp_response(lmtp, &res);
1427 return LMTP_OK;
1428 }
1429
1430 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 354 Start mail input; end with <CRLF>.<CRLF>
1431 */
1432 logbook(ctx->l2, L2_LEVEL_TRACE, "tell remote to send message now");
1433 res.statuscode = "354";
1434 res.dsncode = NULL; /* DSN not used for data */
1435 res.statusmsg = "Enter mail, end with \".\" on a line by itself";
1436 lmtp_response(lmtp, &res);
1437
1438 logbook(ctx->l2, L2_LEVEL_TRACE, "read message with maximum size to accept = %d", ctx->option_maxmessagesize);
1439 rc = lmtp_readmsg(lmtp, &ctx->msg->cpMsg, ctx->option_maxmessagesize);
1440
1441 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 552 Requested mail action aborted: exceeded storage allocation
1442 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1443 * RFC1893 3.5 Network and Routing Status X.2.3 Message length exceeds administrative limit.
1444 */
1445 logbook(ctx->l2, L2_LEVEL_TRACE, "checking for excessive message size");
1446 if (rc == LMTP_ERR_OVERFLOW) {
1447 str_format(errorstring, sizeof(errorstring), "Message length exceeds administrative limit. %s", lmtp_error(rc));
1448 res.statuscode = "552";
1449 res.dsncode = "5.2.3";
1450 res.statusmsg = errorstring;
1451 rcpt = NULL;
1452 while ((rcpt = argz_next(ctx->msg->azRcpt, ctx->msg->asRcpt, rcpt)) != NULL) {
1453 lmtp_response(lmtp, &res);
1454 }
1455 return LMTP_OK;
1456 }
1457
1458 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 451 Requested action aborted: local error in processing
1459 * RFC1893 2. Status Codes 4.X.X Persistent Transient Failure
1460 * RFC1893 3.5 Network and Routing Status X.3.2 System not accepting network messages
1461 */
1462 logbook(ctx->l2, L2_LEVEL_TRACE, "checking for system error");
1463 if (rc == LMTP_ERR_SYSTEM) {
1464 str_format(errorstring, sizeof(errorstring), "System error reading message: %s", strerror(errno));
1465 res.statuscode = "451";
1466 res.dsncode = "4.3.2";
1467 res.statusmsg = errorstring;
1468 rcpt = NULL;
1469 while ((rcpt = argz_next(ctx->msg->azRcpt, ctx->msg->asRcpt, rcpt)) != NULL) {
1470 lmtp_response(lmtp, &res);
1471 }
1472 return LMTP_OK;
1473 }
1474
1475 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 451 Requested action aborted: local error in processing
1476 * RFC1893 2. Status Codes 4.X.X Persistent Transient Failure
1477 * RFC1893 3.5 Network and Routing Status X.3.2 System not accepting network messages
1478 */
1479 logbook(ctx->l2, L2_LEVEL_TRACE, "checking for other error");
1480 if(rc != LMTP_OK) {
1481 str_format(errorstring, sizeof(errorstring), "Unknown error reading message: %s", lmtp_error(rc));
1482 res.statuscode = "451";
1483 res.dsncode = "4.3.2";
1484 res.statusmsg = errorstring;
1485 rcpt = NULL;
1486 while ((rcpt = argz_next(ctx->msg->azRcpt, ctx->msg->asRcpt, rcpt)) != NULL) {
1487 lmtp_response(lmtp, &res);
1488 }
1489 return LMTP_OK;
1490 }
1491
1492 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 554 Transaction failed
1493 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1494 * RFC1893 3.5 Network and Routing Status X.6.5 Conversion Failed
1495 */
1496 logbook(ctx->l2, L2_LEVEL_TRACE, "split message");
1497 if ((rc = msg_split(ctx->msg)) != MSG_OK) {
1498 str_format(errorstring, sizeof(errorstring), "Error splitting message: %s", msg_error(rc));
1499 res.statuscode = "554";
1500 res.dsncode = "5.6.5";
1501 res.statusmsg = errorstring;
1502 rcpt = NULL;
1503 while ((rcpt = argz_next(ctx->msg->azRcpt, ctx->msg->asRcpt, rcpt)) != NULL) {
1504 lmtp_response(lmtp, &res);
1505 }
1506 return LMTP_OK;
1507 }
1508
1509 if (ctx->option_groupmode == GROUPMODE_ENVELOPE) {
1510 if ((cp = malloc(ctx->msg->asEnvgroups + 1)) == NULL) {
1511 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 452 Requested action not taken: insufficient system storage
1512 * RFC1893 2. Status Codes 4.X.X Persistent Transient Failure
1513 * RFC1893 3.5 Network and Routing Status X.3.1 Mail system full
1514 */
1515 ctx->msgcount++;
1516 if ((ctx->msg = msg_create(ctx->prival)) == NULL) {
1517 res.statuscode = "452";
1518 res.dsncode = "4.3.1";
1519 res.statusmsg = "Internal error - memory.";
1520 lmtp_response(lmtp, &res);
1521 return LMTP_ERR_MEM;
1522 }
1523 }
1524 ctx->msg->azNewsgroups = memcpy(cp, ctx->msg->azEnvgroups != NULL ? ctx->msg->azEnvgroups : "", ctx->msg->asEnvgroups);
1525 ctx->msg->asNewsgroups = ctx->msg->asEnvgroups;
1526 }
1527 else if (ctx->option_groupmode == GROUPMODE_ARG) {
1528 if ((cp = malloc(ctx->asGroupargs + 1)) == NULL) {
1529 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 452 Requested action not taken: insufficient system storage
1530 * RFC1893 2. Status Codes 4.X.X Persistent Transient Failure
1531 * RFC1893 3.5 Network and Routing Status X.3.1 Mail system full
1532 */
1533 ctx->msgcount++;
1534 if ((ctx->msg = msg_create(ctx->prival)) == NULL) {
1535 res.statuscode = "452";
1536 res.dsncode = "4.3.1";
1537 res.statusmsg = "Internal error - memory.";
1538 lmtp_response(lmtp, &res);
1539 return LMTP_ERR_MEM;
1540 }
1541 }
1542 ctx->msg->azNewsgroups = memcpy(cp, ctx->azGroupargs != NULL ? ctx->azGroupargs : "", ctx->asGroupargs);
1543 ctx->msg->asNewsgroups = ctx->asGroupargs;
1544 }
1545 else { /* == GROUPMODE_HEADER */
1546 cp = ctx->msg->azNewsgroups;
1547 while (cp != NULL) {
1548 if (!groupmatch(ctx->azGroupargs, ctx->asGroupargs, cp)) {
1549 if (argz_next(ctx->msg->azNewsgroups, ctx->msg->asNewsgroups, cp) == NULL) {
1550 argz_delete(&ctx->msg->azNewsgroups, &ctx->msg->asNewsgroups, cp);
1551 break;
1552 }
1553 else
1554 argz_delete(&ctx->msg->azNewsgroups, &ctx->msg->asNewsgroups, cp);
1555 } else {
1556 cp = argz_next(ctx->msg->azNewsgroups, ctx->msg->asNewsgroups, cp);
1557 }
1558 }
1559 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 550 Requested action not taken: mailbox unavailable
1560 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1561 * RFC1893 3.5 Network and Routing Status X.7.2 Mailing list expansion prohibited
1562 */
1563 if (ctx->msg->asNewsgroups == 0) {
1564 rcpt = NULL;
1565 while ((rcpt = argz_next(ctx->msg->azRcpt, ctx->msg->asRcpt, rcpt)) != NULL) {
1566 res.statuscode = "550";
1567 res.dsncode = "5.7.2";
1568 res.statusmsg = "Header did not match any valid group.";
1569 lmtp_response(lmtp, &res);
1570 }
1571 return LMTP_OK;
1572 }
1573 }
1574
1575 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 550 Requested action not taken: mailbox unavailable
1576 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1577 * RFC1893 3.5 Network and Routing Status X.7.1 Delivery not authorized, message refused
1578 */
1579 logbook(ctx->l2, L2_LEVEL_TRACE, "checking if restricted header causes reject");
1580 if (ctx->option_restrictheader != NULL) {
1581 bOk = FALSE;
1582 cp = NULL;
1583 while ((cp = argz_next(ctx->msg->azHeaders, ctx->msg->asHeaders, cp)) != NULL) {
1584 cpRestrictheader = cp;
1585 if ((cp = argz_next(ctx->msg->azHeaders, ctx->msg->asHeaders, cp)) == NULL)
1586 break;
1587 cpRestrictvalue = cp;
1588 str_format(errorstring, sizeof(errorstring), "%s %s", cpRestrictheader, cpRestrictvalue);
1589 if (str_parse(errorstring, ctx->option_restrictheader) <= 0) {
1590 logbook(ctx->l2, L2_LEVEL_TRACE, "\"%s\" matching against \"%s\" NO", errorstring, ctx->option_restrictheader);
1591 }
1592 else {
1593 logbook(ctx->l2, L2_LEVEL_TRACE, "\"%s\" matching against \"%s\": YES", errorstring, ctx->option_restrictheader);
1594 bOk = TRUE;
1595 break;
1596 }
1597 }
1598 if (bOk) {
1599 logbook(ctx->l2, L2_LEVEL_TRACE, "restricted header found");
1600 rcpt = NULL;
1601 while ((rcpt = argz_next(ctx->msg->azRcpt, ctx->msg->asRcpt, rcpt)) != NULL) {
1602 res.statuscode = "550";
1603 res.dsncode = "5.7.1";
1604 res.statusmsg = "Restricted header matched, message rejected.";
1605 lmtp_response(lmtp, &res);
1606 }
1607 return LMTP_OK;
1608 }
1609 }
1610
1611 /* rewrite headers */
1612 logbook(ctx->l2, L2_LEVEL_TRACE, "appying header rewrite rules");
1613 msg_headermatrixbuildup(ctx->msg);
1614 headerrewrite(ctx);
1615 msg_headermatrixteardwn(ctx->msg);
1616
1617 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 554 Transaction failed
1618 * RFC1893 2. Status Codes 5.X.X Permanent Failure
1619 * RFC1893 3.5 Network and Routing Status X.6.5 Conversion Failed
1620 */
1621 logbook(ctx->l2, L2_LEVEL_TRACE, "join message");
1622 if ((rc = msg_join(ctx->msg)) != MSG_OK) {
1623 str_format(errorstring, sizeof(errorstring), "Error joining message: %s", msg_error(rc));
1624 res.statuscode = "554";
1625 res.dsncode = "5.6.5";
1626 res.statusmsg = errorstring;
1627 rcpt = NULL;
1628 while ((rcpt = argz_next(ctx->msg->azRcpt, ctx->msg->asRcpt, rcpt)) != NULL) {
1629 lmtp_response(lmtp, &res);
1630 }
1631 return LMTP_OK;
1632 }
1633
1634 logbook(ctx->l2, L2_LEVEL_TRACE, "deliver message");
1635 bSuccess = NNTP_ERR_DELIVERY; /* assume a hard error for the worst case */
1636 for (i = 0; i < ctx->nns; i++) {
1637 switch (ctx->option_operationmode) {
1638 case OPERATIONMODE_FAKE:
1639 ctx->pns[i].rc = NNTP_FAKE;
1640 break;
1641 case OPERATIONMODE_POST:
1642 if (ctx->pns[i].nntp)
1643 ctx->pns[i].rc = nntp_post(ctx->pns[i].nntp, ctx->msg);
1644 break;
1645 case OPERATIONMODE_FEED:
1646 if (ctx->pns[i].nntp)
1647 ctx->pns[i].rc = nntp_feed(ctx->pns[i].nntp, ctx->msg);
1648 break;
1649 }
1650 if (ctx->pns[i].rc == NNTP_OK)
1651 bSuccess = NNTP_OK;
1652 if ( bSuccess != NNTP_OK
1653 && (
1654 (ctx->pns[i].rc == NNTP_ERR_SYSTEM)
1655 || (ctx->pns[i].rc == NNTP_DEFER)
1656 )
1657 )
1658 bSuccess = NNTP_DEFER;
1659 }
1660
1661 if (ctx->option_operationmode == OPERATIONMODE_FAKE) {
1662 str_format(errorstring, sizeof(errorstring),
1663 "NNTP running in fake mode, delivery of %s [%d bytes] %s but delivery status forced to",
1664 ctx->msg->cpMsgid,
1665 strlen(ctx->msg->cpMsg),
1666 ((bSuccess == NNTP_OK) ? "succeeded" :
1667 (bSuccess == NNTP_DEFER) ? "deferred" : "failed"));
1668 switch (ctx->option_operationmodefakestatus[0]) {
1669 case '5':
1670 bSuccess = NNTP_ERR_UNKNOWN;
1671 logbook(ctx->l2, L2_LEVEL_NOTICE, "%s %s", errorstring, "failed");
1672 break;
1673 case '4':
1674 bSuccess = NNTP_DEFER;
1675 logbook(ctx->l2, L2_LEVEL_NOTICE, "%s %s", errorstring, "deferred");
1676 break;
1677 default:
1678 bSuccess = NNTP_OK;
1679 logbook(ctx->l2, L2_LEVEL_NOTICE, "%s %s", errorstring, "succeeded");
1680 break;
1681 }
1682 } else {
1683 str_format(errorstring, sizeof(errorstring), "%sdelivery of %s [%d bytes]",
1684 ((ctx->option_operationmode == OPERATIONMODE_POST) ? "post " :
1685 (ctx->option_operationmode == OPERATIONMODE_FEED) ? "feed " : ""),
1686 ctx->msg->cpMsgid,
1687 strlen(ctx->msg->cpMsg));
1688 if (bSuccess == NNTP_OK)
1689 logbook(ctx->l2, L2_LEVEL_NOTICE, "%s %s", errorstring, "succeeded");
1690 else if(bSuccess == NNTP_DEFER)
1691 logbook(ctx->l2, L2_LEVEL_WARNING, "%s %s", errorstring, "deferred");
1692 else
1693 logbook(ctx->l2, L2_LEVEL_ERROR, "%s %s", errorstring, "failed");
1694 }
1695
1696
1697 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 250 Requested mail action okay, completed
1698 * 451 Requested action aborted: local error in processing
1699 * 554 Transaction failed
1700 * RFC1893 2. Status Codes 2.X.X Success
1701 * 4.X.X Persistent Transient Failure
1702 * 5.X.X Permanent Failure
1703 * RFC1893 3.5 Network and Routing Status X.0.0 Other undefined Status
1704 * X.4.2 Bad connection
1705 */
1706 rcpt = NULL;
1707 while ((rcpt = argz_next(ctx->msg->azRcpt, ctx->msg->asRcpt, rcpt)) != NULL) {
1708 logbook(ctx->l2, L2_LEVEL_DEBUG, "ctx->option_operationmode=%d", ctx->option_operationmode);
1709 if (ctx->option_operationmode == OPERATIONMODE_FAKE) {
1710 res.statuscode = ctx->option_operationmodefakestatus;
1711 res.dsncode = ctx->option_operationmodefakedsn;
1712 str_format(errorstring, sizeof(errorstring),
1713 "NNTP noop fake return for %s", rcpt);
1714 } else {
1715 switch (bSuccess) {
1716 case NNTP_OK:
1717 str_format(errorstring, sizeof(errorstring),
1718 "Message accepted for delivery to %s", rcpt);
1719 res.statuscode = "250";
1720 res.dsncode = "2.0.0";
1721 break;
1722 case NNTP_DEFER:
1723 str_format(errorstring, sizeof(errorstring),
1724 "Requested action aborted for %s, local error in processing.", rcpt);
1725 res.statuscode = "451";
1726 res.dsncode = "4.4.2";
1727 break;
1728 default:
1729 str_format(errorstring, sizeof(errorstring),
1730 "Error sending article for %s.", rcpt);
1731 res.statuscode = "554";
1732 res.dsncode = "5.4.2";
1733 break;
1734 }
1735 }
1736 azErr = NULL;
1737 asErr = 0;
1738 argz_add(&azErr, &asErr, errorstring);
1739 for (i = 0; i < ctx->nns; i++) {
1740 if (ctx->pns[i].rc != NNTP_OK) {
1741 var_rc_t var_rc;
1742 char *res_ptr;
1743 size_t res_len;
1744 str_format(errorstring, sizeof(errorstring),
1745 "destination#%d ${option.destination[%d]} returned %s\n"
1746 "destination#%d ${option.destination[%d]} lastresp \"%s\"",
1747 i, i, nntp_error(ctx->pns[i].rc),
1748 i, i, nntp_lastresp(ctx->pns[i].nntp));
1749 if ((var_rc = var_expand(ctx->config_varctx, errorstring, strlen(errorstring), &res_ptr, &res_len, FALSE)) != VAR_OK) {
1750 str_format(errorstring, sizeof(errorstring),
1751 "destination#%d returned %s\n"
1752 "destination#%d lastresp \"%s\"",
1753 i, nntp_error(ctx->pns[i].rc),
1754 i, nntp_lastresp(ctx->pns[i].nntp));
1755 }
1756 else {
1757 str_copy(errorstring, res_ptr, sizeof(errorstring) < res_len ? sizeof(errorstring) : res_len);
1758 free(res_ptr);
1759 }
1760 argz_add(&azErr, &asErr, errorstring);
1761 }
1762 }
1763 if (azErr != NULL) {
1764 argz_stringify(azErr, asErr, '\n');
1765 res.statusmsg = azErr;
1766 lmtp_response(lmtp, &res);
1767 free(azErr);
1768 azErr = NULL;
1769 asErr = 0;
1770 }
1771 else {
1772 res.statusmsg = errorstring;
1773 lmtp_response(lmtp, &res);
1774 }
1775 }
1776
1777 msg_destroy(ctx->msg);
1778 ctx->msg = NULL;
1779
1780 return LMTP_OK;
1781 }
1782
lmtp_cb_noop(lmtp_t * lmtp,lmtp_io_t * io,lmtp_req_t * req,void * _ctx)1783 static lmtp_rc_t lmtp_cb_noop(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
1784 {
1785 lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
1786 lmtp_res_t res;
1787 lmtp_rc_t rc = LMTP_OK;
1788
1789 logbook(ctx->l2, L2_LEVEL_INFO, "LMTP service executing NOOP command < %s", req->msg);
1790
1791 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 250 Requested mail action okay, completed
1792 * RFC1893 2. Status Codes 2.X.X Success
1793 * RFC1893 3.5 Network and Routing Status X.0.0 Other undefined Status
1794 */
1795 res.statuscode = "250";
1796 res.dsncode = "2.0.0";
1797 res.statusmsg = "OK. Nice talking to you.";
1798 lmtp_response(lmtp, &res);
1799 return rc;
1800 }
1801
lmtp_cb_rset(lmtp_t * lmtp,lmtp_io_t * io,lmtp_req_t * req,void * _ctx)1802 static lmtp_rc_t lmtp_cb_rset(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
1803 {
1804 lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
1805 lmtp_res_t res;
1806 lmtp_rc_t rc = LMTP_OK;
1807
1808 logbook(ctx->l2, L2_LEVEL_INFO, "LMTP service executing RSET command < %s", req->msg);
1809
1810 lmtp_gfs_rset(ctx);
1811
1812 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 250 Requested mail action okay, completed
1813 * RFC1893 2. Status Codes 2.X.X Success
1814 * RFC1893 3.5 Network and Routing Status X.0.0 Other undefined Status
1815 */
1816 res.statuscode = "250";
1817 res.dsncode = "2.0.0";
1818 res.statusmsg = "Reset state.";
1819 lmtp_response(lmtp, &res);
1820 return rc;
1821 }
1822
lmtp_gfs_rset(lmtp2nntp_t * ctx)1823 static void lmtp_gfs_rset(lmtp2nntp_t *ctx)
1824 {
1825 logbook(ctx->l2, L2_LEVEL_TRACE, "LMTP service RSET command - graceful shutdown");
1826
1827 if (ctx->msg != NULL) {
1828 msg_destroy(ctx->msg);
1829 ctx->msg = NULL;
1830 }
1831 }
1832
lmtp_cb_quit(lmtp_t * lmtp,lmtp_io_t * io,lmtp_req_t * req,void * _ctx)1833 static lmtp_rc_t lmtp_cb_quit(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
1834 {
1835 lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
1836 lmtp_res_t res;
1837 lmtp_rc_t rc = LMTP_EOF;
1838
1839 logbook(ctx->l2, L2_LEVEL_INFO, "LMTP service executing QUIT command < %s", req->msg);
1840
1841 lmtp_gfs_quit(ctx);
1842
1843 /* RFC0821 4.2.1. REPLY CODES BY FUNCTION GROUPS 221 <domain> Service closing transmission channel
1844 * RFC1893 2. Status Codes 2.X.X Success
1845 * RFC1893 3.5 Network and Routing Status X.0.0 Other undefined Status
1846 */
1847 res.statuscode = "221";
1848 res.dsncode = "2.0.0";
1849 res.statusmsg = "LMTP Service closing transmission channel.";
1850 lmtp_response(lmtp, &res);
1851 return rc;
1852 }
1853
lmtp_gfs_quit(lmtp2nntp_t * ctx)1854 static void lmtp_gfs_quit(lmtp2nntp_t *ctx)
1855 {
1856 logbook(ctx->l2, L2_LEVEL_TRACE, "LMTP service QUIT command - graceful shutdown");
1857
1858 lmtp_gfs_rset(ctx);
1859 resetsession(&ctx->session);
1860 }
1861