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