Back to index

courier  0.68.2
localmail.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2012 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #if    HAVE_CONFIG_H
00007 #include      "config.h"
00008 #endif
00009 #include      <stdio.h>
00010 #include      <stdlib.h>
00011 #include      <string.h>
00012 #include      <signal.h>
00013 #include      <ctype.h>
00014 #include      <sys/types.h>
00015 #include      <sys/stat.h>
00016 #include      <fcntl.h>
00017 #include      <errno.h>
00018 #include      <pwd.h>
00019 #include      <grp.h>
00020 #if TIME_WITH_SYS_TIME
00021 #include      <sys/time.h>
00022 #include      <time.h>
00023 #else
00024 #if HAVE_SYS_TIME_H
00025 #include      <sys/time.h>
00026 #else
00027 #include      <time.h>
00028 #endif
00029 #endif
00030 #include      "courier.h"
00031 #include      "libexecdir.h"
00032 #include      "comctlfile.h"
00033 #include      "comqueuename.h"
00034 #include      "comsubmitclient.h"
00035 #include      "moduledel.h"
00036 #include      "comreadtime.h"
00037 #include      "waitlib/waitlib.h"
00038 #include      "numlib/numlib.h"
00039 #include      "comverp.h"
00040 
00041 #if    HAVE_SYS_FILE_H
00042 #include      <sys/file.h>
00043 #endif
00044 
00045 #if    HAVE_UNISTD_H
00046 #include      <unistd.h>
00047 #endif
00048 
00049 #if HAVE_SYSEXITS_H
00050 #include      <sysexits.h>
00051 #else
00052 #define       EX_TEMPFAIL   75
00053 #define       EX_NOUSER     67
00054 #define       EX_CANTCREAT  73
00055 #define       EX_SOFTWARE   70
00056 #endif
00057 
00058 static const char *courier_home;
00059 
00060 static void wait_delivery(pid_t, struct ctlfile *, unsigned, int, int,
00061        const char *, const char *);
00062 
00063 int main(int argc, char **argv)
00064 {
00065 struct moduledel *p;
00066 
00067        clog_open_syslog("courierlocal");
00068 
00069        if (chdir(courier_home=getenv("COURIER_HOME")))
00070               clog_msg_errno();
00071 
00072        if (atol(getenv("MAXRCPT")) > 1)
00073        {
00074               clog_msg_start_err();
00075               clog_msg_str("Invalid configuration in config, set MAXRCPT=1");
00076               clog_msg_send();
00077               exit(1);
00078        }
00079 
00080        module_init(0);
00081 
00082        module_delivery_timeout(config_readtime("localtimeout", 15*60));
00083 
00084        while ((p=module_getdel()) != NULL)
00085        {
00086        unsigned delid=atol(p->delid);
00087        unsigned rcptnum;
00088        struct ctlfile ctf;
00089        int    pipe1[2], pipe2[2];
00090        pid_t  pid;
00091        int datfd;
00092        struct stat stat_buf;
00093 
00094               pid=module_fork(delid, 0);
00095               if (pid < 0)
00096               {
00097                      clog_msg_prerrno();
00098                      module_completed(delid, delid);
00099                      continue;
00100               }
00101 
00102               if (pid)      continue;
00103 
00104 #if     HAVE_SETPGRP
00105 #if     SETPGRP_VOID
00106               setpgrp();
00107 #else
00108               setpgrp(0, 0);
00109 #endif
00110 #endif
00111 
00112               if (p->nreceipients != 1)
00113               {
00114                      clog_msg_start_err();
00115                      clog_msg_str("Invalid message from courierd.");
00116                      clog_msg_send();
00117                      _exit(0);
00118               }
00119 
00120               rcptnum=atol(p->receipients[0]);
00121               if (ctlfile_openi(p->inum, &ctf, 0))
00122               {
00123                      clog_msg_errno();
00124                      _exit(0);
00125               }
00126               ctlfile_setvhost(&ctf);
00127 
00128               if (pipe(pipe1) < 0 || pipe(pipe2) < 0
00129                   || (pid=fork()) < 0)
00130               {
00131                      clog_msg_prerrno();
00132                      ctlfile_append_reply(&ctf, rcptnum,
00133                             "Can't run courierdeliver.",
00134                             COMCTLFILE_DELDEFERRED, 0);
00135                      ctlfile_close(&ctf);
00136                      _exit(0);
00137                      return (0);
00138               }
00139 
00140               if ((datfd=open(qmsgsdatname(p->inum), O_RDONLY)) < 0)
00141               {
00142                      clog_msg_prerrno();
00143                      ctlfile_append_reply(&ctf, rcptnum,
00144                                         "Unable to read message file.",
00145                                         COMCTLFILE_DELDEFERRED, 0);
00146                      ctlfile_close(&ctf);
00147                      _exit(0);
00148                      return (0);
00149               }
00150 
00151               if (pid == 0)
00152               {
00153               const char *host, *homedir, *maildir, *quota;
00154               char   *buf, *s;
00155 
00156               char   *username, *ext;
00157               uid_t  u;
00158               gid_t  g;
00159 
00160                      close(pipe1[0]);
00161                      close(pipe2[0]);
00162                      dup2(pipe2[1], 2);
00163                      close(pipe2[1]);
00164                      dup2(pipe1[1], 1);
00165                      close(pipe1[1]);
00166                      close(0);
00167                      if (dup(datfd) != 0)
00168                      {
00169                             clog_msg_start_err();
00170                             clog_msg_str("Unable to read message file.");
00171                             clog_msg_send();
00172                             _exit(EX_TEMPFAIL);
00173                      }
00174                      close(ctf.fd);
00175                      close(datfd);
00176 
00177                      /* Contents of host: */
00178                      /* acct!ext!uid!gid!homedir!maildir!quota */
00179 
00180                      host=p->host;
00181 
00182                      buf=strdup(host);
00183                      if (!buf)
00184                      {
00185                             clog_msg_prerrno();
00186                             _exit(EX_TEMPFAIL);
00187                      }
00188 
00189                      s=strchr(buf, '!');
00190                      username=buf;
00191                      if (s) *s++=0;
00192                      ext=s;
00193                      if (s) s=strchr(s, '!');
00194                      if (s) *s++=0;
00195 
00196                      u=0;
00197                      while (s && *s != '!')
00198                      {
00199                             if (isdigit((int)(unsigned char)*s))
00200                                    u=u*10 + (*s - '0');
00201                             ++s;
00202                      }
00203                      if (s) *s++=0;
00204                      g=0;
00205                      while (s && *s != '!')
00206                      {
00207                             if (isdigit((int)(unsigned char)*s))
00208                                    g=g*10 + (*s - '0');
00209                             ++s;
00210                      }
00211 
00212                      if (s) *s++=0;
00213 
00214                      homedir=s;
00215 
00216                      if (s) s=strchr(s, '!');
00217                      if (s) *s++=0;
00218 
00219                      maildir=s;
00220 
00221                      if (s) s=strchr(s, '!');
00222                      if (s) *s++=0;
00223 
00224                      quota=s;
00225                      
00226                      if (!s)
00227                      {
00228                             clog_msg_start_err();
00229                             clog_msg_str("Invalid local recipient address.");
00230                             clog_msg_send();
00231                             _exit(EX_TEMPFAIL);
00232                      }
00233 
00234                      if (chdir(homedir))
00235                      {
00236                             clog_msg_str(homedir);
00237                             clog_msg_str(": ");
00238                             clog_msg_prerrno();
00239                             _exit(EX_TEMPFAIL);
00240                      }
00241 
00242                      libmail_changeuidgid(u, g);
00243 
00244                      execl( MODULEDIR "/local/courierdeliver",
00245                             "courierdeliver",
00246                             username,
00247                             homedir,
00248                             ext,
00249                             ctf.receipients[rcptnum],
00250                             verp_getsender(&ctf, ctf.receipients[rcptnum]),
00251                             quota,
00252                             maildir,
00253                             (const char *)0);
00254 
00255                      clog_msg_start_err();
00256                      clog_msg_prerrno();
00257                      clog_msg_send();
00258                      _exit(EX_TEMPFAIL);
00259               }
00260 
00261               close(pipe1[1]);
00262               close(pipe2[1]);
00263 
00264               libmail_changeuidgid(MAILUID, MAILGID);
00265               if (fstat(datfd, &stat_buf) == 0)
00266                      ctf.msgsize=stat_buf.st_size;
00267 
00268               close(datfd);
00269               wait_delivery(pid, &ctf, rcptnum, pipe2[0], pipe1[0],
00270                             p->host, p->receipients[1]);
00271               ctlfile_close(&ctf);
00272               _exit(0);
00273        }
00274        return (0);
00275 }
00276 
00277 static char msgbuf[4096];
00278 static char fwdbuf[1024];
00279 static char errbuf[1024];
00280 static char *errptr;
00281 static size_t errleft;
00282 
00283 unsigned msglen, fwdlen;
00284 
00285 
00286 static void save_submit_errmsg(const char *p)
00287 {
00288        size_t l=strlen(p ? p:"");
00289 
00290        if (l > errleft)
00291               l=errleft;
00292 
00293        if (l > 0)
00294        {
00295               strcpy(errptr, p);
00296               errptr += l;
00297               errleft -= l;
00298        }
00299 }
00300 
00301 static void savemsg(const char *p, unsigned l)
00302 {
00303        if (l > sizeof(msgbuf)-1-msglen)
00304               l=sizeof(msgbuf)-1-msglen;
00305 
00306        if (l) memcpy(msgbuf+msglen, p, l);
00307        msglen += l;
00308 }
00309 
00310 int    submit_started=0, submit_err=0;
00311 
00312 static void dofwd(const char *addr, const char *from, const char *fromuser,
00313        const char *origuser)
00314 {
00315        if (!submit_started)
00316        {
00317        char   *args[5];
00318 
00319        static const char *envvars[]={
00320               "DSNNOTIFY",
00321               "DSNRET",
00322               "NOADDATE",
00323               "NOADDMSGID",
00324               "MIME",
00325               0};
00326 
00327        char   *envs[sizeof(envvars)/sizeof(envvars[0])];
00328        int    i, j;
00329 
00330               for (i=j=0; envvars[i]; i++)
00331               {
00332               const char *p=getenv(envvars[i]);
00333               char   *q;
00334 
00335                      if (!p)       continue;
00336                      q=strcat(strcat(strcpy(courier_malloc(
00337                                    strlen(envvars[i])+strlen(p)+2),
00338                                    envvars[i]), "="), p);
00339                      envs[j]=q;
00340                      j++;
00341               }
00342               envs[j]=0;
00343 
00344 
00345               args[0]="submit";
00346               args[1]="local";
00347               args[2]="dns; localhost (localhost [127.0.0.1])";
00348               args[3]=strcat(strcpy(courier_malloc(
00349                             sizeof("forwarded by ")+strlen(fromuser)),
00350                                    "forwarded by "), fromuser);
00351               args[4]=0;
00352 
00353               errptr=errbuf;
00354               errleft=sizeof(errbuf)-1;
00355 
00356               save_submit_errmsg("The following error occured when trying to forward this message: \n");
00357               strcpy(errptr, "UNKNOWN ERROR - no further description is available");
00358 
00359               if (submit_fork(args, envs, save_submit_errmsg) ||
00360                      (submit_write_message(from), submit_readrcprinterr()))
00361               {
00362                      submit_err=1;
00363                      return;
00364               }
00365               while (j)
00366               {
00367                      free(envs[--j]);
00368               }
00369               submit_err=0;
00370               submit_started=1;
00371        }
00372 
00373        if (!submit_err)
00374        {
00375        char   *p;
00376 
00377               p=strcat(strcat(strcpy(courier_malloc(
00378                      strlen(addr)+strlen(origuser)+4), addr),
00379                             "\tF\t"), origuser);
00380               submit_write_message(p);
00381               free(p);
00382               if (submit_readrcprinterr())
00383               {
00384                      submit_err=1;
00385               }
00386        }
00387 }
00388 
00389 static void fwdmsg(const char *p, unsigned l, const char *from,
00390        const char *fwduser, const char *origuser)
00391 {
00392        while (l)
00393        {
00394               if (fwdlen < sizeof(fwdbuf))
00395                      fwdbuf[fwdlen++]= *p;
00396               if (*p == '\n')
00397               {
00398                      fwdbuf[--fwdlen]=0;
00399                      dofwd(fwdbuf, from, fwduser, origuser);
00400                      fwdlen=0;
00401               }
00402               ++p;
00403               --l;
00404        }
00405 }
00406 
00407 
00408 static void wait_delivery(pid_t pid,
00409        struct ctlfile *ctf, unsigned rcptnum, int msgpipe, int fwdpipe,
00410        const char *user, const char *ext)
00411 {
00412 fd_set fds;
00413 int    maxfd= msgpipe > fwdpipe ? msgpipe:fwdpipe;
00414 char   buf[BUFSIZ];
00415 int    waitstat;
00416 char   *sender=verp_getsender(ctf, ctf->receipients[rcptnum]);
00417 
00418 const  char *oreceipient;
00419 char   *oreceipients=0;
00420 
00421        if ( ctf->oreceipients[rcptnum] == 0 ||
00422                      ctf->oreceipients[rcptnum][0])
00423        {
00424               oreceipient=ctf->oreceipients[rcptnum];
00425        }
00426        else
00427        {
00428               oreceipient=oreceipients=dsnencodeorigaddr(
00429                      ctf->receipients[rcptnum]);
00430        }
00431 
00432        ++maxfd;
00433        msglen=0;
00434        fwdlen=0;
00435        while (msgpipe >= 0 && fwdpipe >= 0)
00436        {
00437        int    l;
00438 
00439               FD_ZERO(&fds);
00440               if (msgpipe >= 0)
00441                      FD_SET(msgpipe, &fds);
00442               if (fwdpipe >= 0)
00443                      FD_SET(fwdpipe, &fds);
00444 
00445               if (select(maxfd, &fds, 0, 0, 0) < 0)
00446               {
00447                      clog_msg_prerrno();
00448                      continue;
00449               }
00450 
00451               if (msgpipe >= 0 && FD_ISSET(msgpipe, &fds))
00452               {
00453                      if ( (l=read(msgpipe, buf, sizeof(buf))) <= 0)
00454                      {
00455                             close(msgpipe);
00456                             msgpipe=-1;
00457                      }
00458                      else
00459                             savemsg(buf, l);
00460               }
00461               if (fwdpipe >= 0 && FD_ISSET(fwdpipe, &fds))
00462               {
00463                      if ( (l=read(fwdpipe, buf, sizeof(buf))) <= 0)
00464                      {
00465                             close(fwdpipe);
00466                             fwdpipe=-1;
00467                      }
00468                      else
00469                             fwdmsg(buf, l, sender,
00470                                    ctf->receipients[rcptnum],
00471                                    oreceipient);
00472               }
00473        }
00474 
00475        free(sender);
00476        while ( wait(&waitstat) != pid)
00477               ;
00478 
00479        if (msglen)
00480        {
00481        char   *p, *q;
00482 
00483               msgbuf[msglen]=0;
00484               for (p=msgbuf; *p; )
00485               {
00486                      for (q=p; *q; )
00487                      {
00488                             if (*q == '\n')
00489                             {
00490                                    *q++=0;
00491                                    break;
00492                             }
00493                             q++;
00494                      }
00495                      ctlfile_append_info(ctf, rcptnum, p);
00496                      p=q;
00497               }
00498        }
00499 
00500        if (submit_started && !submit_err)
00501        {
00502        FILE   *f=fopen(qmsgsdatname(ctf->n), "r");
00503 
00504               if (!f)
00505                      submit_err=1;
00506               else
00507               {
00508               int    c;
00509 
00510                      fprintf(submit_to, "\nDelivered-To: %s\n",
00511                             ctf->receipients[rcptnum]);
00512                      while ((c=getc(f)) != EOF)
00513                             putc(c, submit_to);
00514                      if (ferror(f) || fflush(submit_to) || fclose(submit_to))
00515                      {
00516                             submit_cancel();
00517                             submit_err=1;
00518                      }
00519                      else if (submit_readrcprinterr())
00520                      {
00521                             submit_wait();
00522                             submit_err=1;
00523                      }
00524                      else if (submit_wait())
00525                             submit_err=1;
00526               }
00527        }
00528 
00529        if (WIFEXITED(waitstat))
00530               switch (WEXITSTATUS(waitstat))     {
00531               case 0:
00532               case 99:
00533                      if (submit_err)
00534                      {
00535                             ctlfile_append_reply(ctf, rcptnum,
00536                                                errbuf,
00537                                                COMCTLFILE_DELFAIL, 0);
00538                      }
00539                      else
00540                      {
00541                             ctlfile_append_reply(ctf, rcptnum,
00542                                    "Message delivered.",
00543                                    COMCTLFILE_DELSUCCESS, " l");
00544                      }
00545                      if (oreceipients)
00546                             free (oreceipients);
00547                      return;
00548               case EX_SOFTWARE:
00549                      ctlfile_append_reply(ctf, rcptnum,
00550                                    "", COMCTLFILE_DELFAIL_NOTRACK, 0);
00551                      if (oreceipients)
00552                             free (oreceipients);
00553                      return;
00554 
00555 
00556               case 64:
00557               case 65:
00558               case 67:
00559               case 68:
00560               case 69:
00561               case 76:
00562               case 77:
00563               case 78:
00564               case 100:
00565               case 112:
00566                      break;
00567               default:
00568                      ctlfile_append_reply(ctf, rcptnum,
00569                                    "", COMCTLFILE_DELDEFERRED, 0);
00570                      if (oreceipients)
00571                             free (oreceipients);
00572                      return;
00573               }
00574 
00575        ctlfile_append_reply(ctf, rcptnum, "", COMCTLFILE_DELFAIL, 0);
00576        if (oreceipients)
00577               free (oreceipients);
00578 }