[CONTACT]

[ABOUT]

[POLICY]

git clone milter milter Log gph

Found at: gopher.r-36.net:70/scm/bmf-milter/file/bmf-milter.c.gph

tbmf-milter.c - bmf-milter - bmf filter milter daemon

git clone git://r-36.net/bmf-milter

Log

Files

Refs

LICENSE

---
tbmf-milter.c (10322B)
---
     1 /*
     2  * Copy me if you can.
     3  * by 20h
     4  */
     5
     6 #include <sys/types.h>
     7 #include <sys/stat.h>
     8 #include <sys/wait.h>
     9 #include <fcntl.h>
    10 #include <errno.h>
    11 #include <stdio.h>
    12 #include <grp.h>
    13 #include <pwd.h>
    14 #include <stdlib.h>
    15 #include <string.h>
    16 #include <stdarg.h>
    17 #include <sysexits.h>
    18 #include <unistd.h>
    19 #include <signal.h>
    20
    21 #include "libmilter/mfapi.h"
    22 #include "libmilter/mfdef.h"
    23
    24 #include "arg.h"
    25
    26 /*
    27  * In case any requires feature is not negotiable, simply do nothing,
    28  * thus always return SMFI_CONTINUE. If we would return any FAIL, the
    29  * message would be rejected.
    30  */
    31 int donothing = 0, dodebug = 0;
    32 char *bmfdb = NULL, *bmfpath = "/usr/bin/bmf";
    33
    34 struct Priv {
    35         /* read from execpipe[0], write to execpipe[1] */
    36         int        execpipe[2];
    37         int        execpid;
    38 };
    39
    40 #define MLFIPRIV ((struct Priv *) smfi_getpriv(ctx))
    41
    42 int
    43 start_bmf(SMFICTX *ctx)
    44 {
    45         struct Priv *priv;
    46         char *ident, *bmfargs[6];
    47         int pid, nullfd, argp;
    48
    49         if (dodebug)
    50                 fprintf(stderr, "start_bmf()\n");
    51
    52         if (donothing) {
    53                 smfi_setpriv(ctx, NULL);
    54                 return 1;
    55         }
    56
    57         priv = malloc(sizeof(*priv));
    58         if (priv == NULL)
    59                 return 1;
    60         memset(priv, '\0', sizeof(*priv));
    61
    62         smfi_setpriv(ctx, priv);
    63
    64         if (pipe(priv->execpipe) < 0) {
    65                 free(priv);
    66                 smfi_setpriv(ctx, NULL);
    67                 return 1;
    68         }
    69
    70         switch ((pid = fork())) {
    71         case 0:
    72                 while(dup2(priv->execpipe[0], 0) < 0 && errno == EINTR);
    73                 close(priv->execpipe[1]);
    74
    75                 argp = 0;
    76                 bmfargs[argp++] = "bmf";
    77                 /* Test for spam mode. */
    78                 bmfargs[argp++] = "-t";
    79
    80                 if (!dodebug) {
    81                         nullfd = open("/dev/null", O_WRONLY);
    82                         if (nullfd < 0) {
    83                                 perror("open");
    84                                 _exit(1);
    85                         }
    86                         while(dup2(priv->execpipe[0], 1) < 0
    87                                         && errno == EINTR);
    88                         while(dup2(priv->execpipe[0], 2) < 0
    89                                         && errno == EINTR);
    90
    91                         /* Verbose for bmf. */
    92                         bmfargs[argp++] = "-v";
    93                 }
    94
    95                 if (bmfdb != NULL) {
    96                         /* Set database directory, if set. */
    97                         bmfargs[argp++] = "-d";
    98                         bmfargs[argp++] = bmfdb;
    99                 }
   100                 bmfargs[argp++] = NULL;
   101
   102                 if (execv(bmfpath, bmfargs) < 0) {
   103                         perror("execv");
   104                         _exit(1);
   105                 }
   106                 break;
   107         case -1:
   108                 free(priv);
   109                 smfi_setpriv(ctx, NULL);
   110                 break;
   111         default:
   112                 if (dodebug)
   113                         fprintf(stderr, "start_bmf(pid = %d)\n", pid);
   114                 priv->execpid = pid;
   115                 close(priv->execpipe[0]);
   116                 break;
   117         }
   118
   119         return 0;
   120 }
   121
   122 sfsistat
   123 mlfi_cleanup(SMFICTX *ctx, int iseom)
   124 {
   125         struct Priv *priv = MLFIPRIV;
   126         int retcode = -1;
   127
   128         if (dodebug)
   129                 fprintf(stderr, "mlfi_cleanup(iseom = %d)\n", iseom);
   130
   131         if (priv == NULL)
   132                 return SMFIS_CONTINUE;
   133         if (dodebug)
   134                 fprintf(stderr, "mlfi_cleanup(closing execpipe[1])\n");
   135         close(priv->execpipe[1]);
   136         priv->execpipe[1] = -1;
   137         if (dodebug)
   138                 fprintf(stderr, "mlfi_cleanup(waitpid)\n");
   139         waitpid(priv->execpid, &retcode, 0);
   140         if (dodebug)
   141                 fprintf(stderr, "mlfi_cleanup(retcode = %d)\n", retcode);
   142
   143         /*
   144          * smfi_addheader is only allowed in eom.
   145          */
   146         if (iseom) {
   147                 if (retcode == 0) {
   148                         if (smfi_addheader(ctx, "X-Spam-Flag",
   149                                                 " YES") == MI_FAILURE) {
   150                                 if (dodebug) {
   151                                         fprintf(stderr,
   152                                         "mlfi_cleanup(x-spam-flag failed)\n");
   153                                 }
   154                         } else {
   155                                 if (dodebug) {
   156                                         fprintf(stderr,
   157                                         "mlfi_cleanup(x-spam-flag = yes added)\n");
   158                                 }
   159                         }
   160                 }
   161                 if (smfi_addheader(ctx, "X-BMF-Processed",
   162                                         " YES") == MI_FAILURE) {
   163                         if (dodebug) {
   164                                 fprintf(stderr,
   165                                 "mlfi_cleanup(x-bmf-processed failed)\n");
   166                         }
   167                 } else {
   168                         if (dodebug) {
   169                                 fprintf(stderr,
   170                                 "mlfi_cleanup(x-bmf-processed = yes added)\n");
   171                         }
   172                 }
   173         }
   174
   175         return SMFIS_CONTINUE;
   176 }
   177
   178 sfsistat
   179 mlfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
   180 {
   181         if (dodebug)
   182                 fprintf(stderr, "mlfi_connect(%s)\n", hostname);
   183
   184         return SMFIS_CONTINUE;
   185 }
   186
   187 sfsistat
   188 mlfi_helo(SMFICTX *ctx, char *helohost)
   189 {
   190         if (dodebug)
   191                 fprintf(stderr, "mlfi_helo(%s)\n", helohost);
   192
   193         smfi_setpriv(ctx, NULL);
   194
   195         return SMFIS_CONTINUE;
   196 }
   197
   198 sfsistat
   199 mlfi_envfrom(SMFICTX *ctx, char *argv[])
   200 {
   201         struct Priv *priv = MLFIPRIV;
   202
   203         if (dodebug)
   204                 fprintf(stderr, "mlfi_envfrom(%s)\n", argv[0]);
   205
   206         if (priv == NULL) {
   207                 if (start_bmf(ctx))
   208                         return SMFIS_CONTINUE;
   209                 priv = MLFIPRIV;
   210         }
   211         dprintf(priv->execpipe[1], "From: %s\n", argv[0]);
   212
   213         return SMFIS_CONTINUE;
   214 }
   215
   216 sfsistat
   217 mlfi_envrcpt(SMFICTX *ctx, char *argv[])
   218 {
   219         struct Priv *priv = MLFIPRIV;
   220
   221         if (dodebug)
   222                 fprintf(stderr, "mlfi_envrcpt(%s)\n", argv[0]);
   223
   224         if (priv == NULL) {
   225                 if (start_bmf(ctx))
   226                         return SMFIS_CONTINUE;
   227                 priv = MLFIPRIV;
   228         }
   229         dprintf(priv->execpipe[1], "To: %s\n", argv[0]);
   230
   231         return SMFIS_CONTINUE;
   232 }
   233
   234 sfsistat
   235 mlfi_header(SMFICTX *ctx, char *headerf, char *headerv)
   236 {
   237         struct Priv *priv = MLFIPRIV;
   238
   239         if (dodebug)
   240                 fprintf(stderr, "mlfi_header(%s = '%s')\n", headerf, headerv);
   241
   242         if (priv == NULL) {
   243                 if (start_bmf(ctx))
   244                         return SMFIS_CONTINUE;
   245                 priv = MLFIPRIV;
   246         }
   247         dprintf(priv->execpipe[1], "%s:%s\n", headerf, headerv);
   248
   249         return SMFIS_CONTINUE;
   250 }
   251
   252 sfsistat
   253 mlfi_eoh(SMFICTX *ctx)
   254 {
   255         struct Priv *priv = MLFIPRIV;
   256
   257         if (dodebug)
   258                 fprintf(stderr, "mlfi_eoh()\n");
   259
   260         if (priv == NULL) {
   261                 if (start_bmf(ctx))
   262                         return SMFIS_CONTINUE;
   263                 priv = MLFIPRIV;
   264         }
   265         dprintf(priv->execpipe[1], "\r\n");
   266
   267         return SMFIS_CONTINUE;
   268 }
   269
   270 sfsistat
   271 mlfi_body(SMFICTX *ctx, unsigned char *bodyp, size_t bodylen)
   272 {
   273         struct Priv *priv = MLFIPRIV;
   274         int written;
   275
   276         if (dodebug)
   277                 fprintf(stderr, "mlfi_body(%ld bytes)\n", bodylen);
   278
   279         if (priv == NULL) {
   280                 if (start_bmf(ctx))
   281                         return SMFIS_CONTINUE;
   282                 priv = MLFIPRIV;
   283         }
   284         for (int written = 0, rw = 0; written < bodylen; written += rw)
   285                 rw = write(priv->execpipe[1], bodyp+written, bodylen-written);
   286
   287         return SMFIS_CONTINUE;
   288 }
   289
   290 sfsistat
   291 mlfi_eom(SMFICTX *ctx)
   292 {
   293         if (dodebug)
   294                 fprintf(stderr, "mlfi_eom()\n");
   295
   296         return mlfi_cleanup(ctx, 1);
   297 }
   298
   299 sfsistat
   300 mlfi_abort(SMFICTX *ctx)
   301 {
   302         if (dodebug)
   303                 fprintf(stderr, "mlfi_abort()\n");
   304
   305         return mlfi_cleanup(ctx, 0);
   306 }
   307
   308 sfsistat
   309 mlfi_close(SMFICTX *ctx)
   310 {
   311         struct Priv *priv = MLFIPRIV;
   312
   313         if (dodebug)
   314                 fprintf(stderr, "mlfi_close()\n");
   315
   316         if (priv != NULL) {
   317                 if (priv->execpipe[1] > 0) {
   318                         if (dodebug) {
   319                                 fprintf(stderr,
   320                                 "mlfi_close(close execpipe[1])\n");
   321                         }
   322                         close(priv->execpipe[1]);
   323                 }
   324                 if (priv->execpid > 0) {
   325                         if (dodebug) {
   326                                 fprintf(stderr,
   327                                 "mlfi_close(kill pid %d)\n", priv->execpid);
   328                         }
   329                         kill(priv->execpid, SIGKILL);
   330                         waitpid(priv->execpid, NULL, 0);
   331                 }
   332                 if (dodebug)
   333                         fprintf(stderr, "mlfi_close(free priv)\n");
   334                 free(priv);
   335                 smfi_setpriv(ctx, NULL);
   336         }
   337
   338         return SMFIS_CONTINUE;
   339 }
   340
   341 sfsistat
   342 mlfi_negotiate(SMFICTX *ctx,
   343                 unsigned long f0,
   344                 unsigned long f1,
   345                 unsigned long f2,
   346                 unsigned long f3,
   347                 unsigned long *pf0,
   348                 unsigned long *pf1,
   349                 unsigned long *pf2,
   350                 unsigned long *pf3)
   351 {
   352         if (dodebug)
   353                 fprintf(stderr, "mlfi_negotiate()\n");
   354
   355         /* milter actions */
   356         *pf0 = 0;
   357         if (f0 & SMFIF_ADDHDRS) {
   358                 *pf0 |= SMFIF_ADDHDRS;
   359         } else {
   360                 donothing = 1;
   361         }
   362
   363         /* milter protocol steps */
   364         *pf1 = f1 & (SMFIP_NOUNKNOWN|SMFIP_NODATA);
   365         if (f1 & SMFIP_HDR_LEADSPC) {
   366                 *pf1 |= SMFIP_HDR_LEADSPC;
   367         } else {
   368                 donothing = 1;
   369         }
   370
   371         /* future */
   372         *pf2 = 0;
   373         *pf3 = 0;
   374
   375         return SMFIS_CONTINUE;
   376 }
   377
   378 struct smfiDesc smfilter =
   379 {
   380         "BMF",                /* filter name */
   381         SMFI_VERSION,        /* version code -- do not change */
   382         SMFIF_ADDHDRS,  /* flags */
   383         mlfi_connect,        /* connection info filter */
   384         mlfi_helo,        /* SMTP HELO command filter */
   385         mlfi_envfrom,        /* envelope sender filter */
   386         mlfi_envrcpt,        /* envelope recipient filter */
   387         mlfi_header,        /* header filter */
   388         mlfi_eoh,        /* end of header */
   389         mlfi_body,        /* body block filter */
   390         mlfi_eom,        /* end of message */
   391         mlfi_abort,        /* message aborted */
   392         mlfi_close,        /* connection cleanup */
   393         NULL,                /* unknown SMTP commands */
   394         NULL,                /* DATA command */
   395         mlfi_negotiate        /* Once, at the start of each SMTP connection */
   396 };
   397
   398 void
   399 sighandler(int sig)
   400 {
   401         int i;
   402
   403         switch (sig) {
   404         case SIGCHLD:
   405                 while (waitpid(-1, NULL, WNOHANG) > 0);
   406                 break;
   407         case SIGINT:
   408         case SIGQUIT:
   409         case SIGABRT:
   410         case SIGTERM:
   411         case SIGKILL:
   412                 smfi_stop();
   413                 break;
   414         default:
   415                 break;
   416         }
   417 }
   418
   419 void
   420 initsignals(void)
   421 {
   422         signal(SIGCHLD, sighandler);
   423         signal(SIGHUP, sighandler);
   424         signal(SIGINT, sighandler);
   425         signal(SIGQUIT, sighandler);
   426         signal(SIGABRT, sighandler);
   427         signal(SIGTERM, sighandler);
   428         signal(SIGKILL, sighandler);
   429
   430         /*
   431          * done by smfi_main():
   432          * signal(SIGPIPE, SIG_IGN);
   433          */
   434 }
   435
   436 void
   437 usage(char *argv0)
   438 {
   439         fprintf(stderr,
   440                 "Usage: %s [-hd] [-b bmfdb] [-c conndef] [-f bmfpath] "
   441                 "[-g group] [-t timeout] [-u user] [-v dbglevel]\n",
   442                 argv0);
   443 }
   444
   445 int
   446 main(int argc, char *argv[])
   447 {
   448         char *argv0, *user = NULL, *group = NULL, *conndef = "inet:9957";
   449         int timeout = -1, dofork = 1;
   450         struct passwd *us = NULL;
   451         struct group *gr = NULL;
   452
   453         ARGBEGIN(argv0) {
   454         case 'b':
   455                 bmfdb = EARGF(usage(argv0));
   456                 break;
   457         case 'c':
   458                 conndef = EARGF(usage(argv0));
   459                 break;
   460         case 'd':
   461                 dofork = 0;
   462                 break;
   463         case 'f':
   464                 bmfpath = EARGF(usage(argv0));
   465                 break;
   466         case 'g':
   467                 group = EARGF(usage(argv0));
   468                 break;
   469         case 't':
   470                 timeout = atoi(EARGF(usage(argv0)));
   471                 break;
   472         case 'u':
   473                 user = EARGF(usage(argv0));
   474                 break;
   475         case 'v':
   476                 smfi_setdbg(atoi(EARGF(argv0)));
   477                 dodebug = 1;
   478                 break;
   479         default:
   480                 usage(argv0);
   481                 return 1;
   482         } ARGEND;
   483
   484         if (group != NULL) {
   485                 errno = 0;
   486                 if ((gr = getgrnam(group)) == NULL) {
   487                         if (errno == 0) {
   488                                 fprintf(stderr, "no such group '%s'\n",
   489                                                 group);
   490                         } else {
   491                                 perror("getgrnam");
   492                         }
   493                         return 1;
   494                 }
   495         }
   496
   497         if (user != NULL) {
   498                 errno = 0;
   499                 if ((us = getpwnam(user)) == NULL) {
   500                         if (errno == 0) {
   501                                 fprintf(stderr, "no such user '%s'\n",
   502                                                 user);
   503                         } else {
   504                                 perror("getpwnam");
   505                         }
   506                         return 1;
   507                 }
   508         }
   509
   510         if (dofork) {
   511                 switch (fork()) {
   512                 case -1:
   513                         perror("fork");
   514                         return 1;
   515                 case 0:
   516                         break;
   517                 default:
   518                         return 0;
   519                 }
   520         }
   521
   522         if (gr != NULL) {
   523                 if (setgroups(1, &gr->gr_gid) != 0 || setgid(gr->gr_gid) != 0) {
   524                         perror("setgroups");
   525                         return -1;
   526                 }
   527         }
   528         if (us != NULL) {
   529                 if (gr == NULL) {
   530                         if (setgroups(1, &us->pw_gid) != 0 ||
   531                             setgid(us->pw_gid) != 0) {
   532                                 perror("setgroups");
   533                                 return -1;
   534                         }
   535                 }
   536                 if (setuid(us->pw_uid) != 0) {
   537                         perror("setuid");
   538                         return -1;
   539                 }
   540         }
   541
   542         if (smfi_setconn(conndef) == MI_FAILURE) {
   543                 perror("smfi_setconn");
   544                 return 1;
   545         }
   546         if (dodebug)
   547                 fprintf(stderr, "conn set to '%s'\n", conndef);
   548
   549         if (timeout > 0) {
   550                 if (smfi_settimeout(timeout) == MI_FAILURE) {
   551                         perror("smfi_settimout");
   552                         return 1;
   553                 }
   554                 if (dodebug)
   555                         fprintf(stderr, "timeout set to %d\n", timeout);
   556         }
   557
   558         if (smfi_register(smfilter) == MI_FAILURE) {
   559                 perror("smfi_register");
   560                 return 1;
   561         }
   562
   563         return smfi_main();
   564 }
   565
.


AD:

NEW PAGES:

[ODDNUGGET]

[GOPHER]