Back to index

courier  0.68.2
local.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2006 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #if    HAVE_CONFIG_H
00007 #include      "config.h"
00008 #endif
00009 
00010 #include      "courier.h"
00011 #include      "rw.h"
00012 #include      "rfc822.h"
00013 #include      <stdlib.h>
00014 #include      <string.h>
00015 #include      <ctype.h>
00016 #include      <errno.h>
00017 #if    HAVE_UNISTD_H
00018 #include      <unistd.h>
00019 #endif
00020 #if    HAVE_FCNTL_H
00021 #include      <fcntl.h>
00022 #endif
00023 #include      <stdio.h>
00024 #include      <pwd.h>
00025 #include      "waitlib/waitlib.h"
00026 #include      "modulelist.h"
00027 #include      "sysconfdir.h"
00028 #include      <courierauth.h>
00029 
00030 #if    HAVE_SYSLOG_H
00031 #include      <syslog.h>
00032 #else
00033 #define       syslog(a, b)
00034 #endif
00035 
00036 #define DEFAULTNAME  "alias@"
00037 
00038 
00039 extern char *local_dotcourier(const char *, const char *, const char **);
00040 
00041 static void rw_local(struct rw_info *, void (*)(struct rw_info *));
00042 static void rw_del_local(struct rw_info *, void (*)(struct rw_info *),
00043               void (*)(struct rw_info *, const struct rfc822token *,
00044                      const struct rfc822token *));
00045 
00046 static int rw_local_filter(const char *,  /* Sending module */
00047                      int,                 /* File descriptor */
00048                      const char *,        /* Host */
00049                      const char *,        /* Address */
00050                      const char *,        /* Envelope sender */
00051                      char *,                     /* Buffer for optional msg */
00052                      unsigned);           /* Sizeof(buffer) */
00053 
00054 struct rw_list *local_rw_install(const struct rw_install_info *p)
00055 {
00056 static struct rw_list local_info={0, "module.local - " COURIER_COPYRIGHT,
00057                       rw_local, rw_del_local, rw_local_filter};
00058 
00059        return (&local_info);
00060 }
00061 
00062 const char *local_rw_init()
00063 {
00064        return (0);
00065 }
00066 
00067 static void rw_local(struct rw_info *p, void (*func)(struct rw_info *))
00068 {
00069        if (p->mode & RW_SUBMIT)
00070        {
00071               if (p->mode & RW_ENVSENDER)
00072               {
00073               char   *q=rfc822_gettok(p->ptr);
00074 
00075                      if (!q)       clog_msg_errno();
00076 
00077 /*********************************************************************
00078 **
00079 ** To filter messages originating from the command line based on the
00080 ** sender, insert code here to call p->rw_info to reject the message.
00081 **
00082 ** The sender can be identified via getuid().  Note, though, that the
00083 ** process is running setgid to MAILGID.
00084 **
00085 *********************************************************************/
00086 
00087                      free(q);
00088               }
00089        }
00090 
00091        rw_local_defaulthost(p, func);
00092 }
00093 
00094 static int local_callback(struct authinfo *, void *);
00095 
00096 struct localauthinfo {
00097        const char *address;
00098        const char *ext;
00099        struct rw_info *rwi;
00100        void (*delfunc)(struct rw_info *, const struct rfc822token *,
00101                      const struct rfc822token *);
00102        int found;
00103        int exists;
00104 } ;
00105 
00106 static int cleanup_set=0;
00107 
00108 /* Before terminating, nicely shut down everything */
00109 
00110 static void cleanup()
00111 {
00112 }
00113 
00114 /*
00115 
00116    Accept delivery for a local address, if:
00117 
00118    A) the address does NOT contain the ! character, AND
00119    B) the address does not contain the @ character, or the domain after the @
00120       is local.
00121 
00122 */
00123 
00124 static void rw_del_local(struct rw_info *rwi,
00125                      void (*nextfunc)(struct rw_info *),
00126               void (*delfunc)(struct rw_info *, const struct rfc822token *,
00127                             const struct rfc822token *))
00128 {
00129 struct rfc822token *p, **prevp;
00130 char   *addr, *ext;
00131 int    i;
00132 struct localauthinfo lai;
00133 char   *hostdomain=NULL;
00134 struct rfc822token   hostdomaint;
00135 #if LOCAL_EXTENSIONS
00136 char *atdomain;
00137 #endif
00138 
00139        if (!cleanup_set)
00140        {
00141               atexit(cleanup);
00142               cleanup_set=1;
00143        }
00144 
00145        prevp=0;
00146        for (p= *(prevp=&rwi->ptr); p; p= *(prevp= &p->next))
00147        {
00148               if (p->token == '!')
00149               {
00150                      (*nextfunc)(rwi);
00151                      return;
00152               }
00153               if (p->token == '@') break;
00154        }
00155 
00156        if (p)
00157        {
00158               /* If not a local domain, ignore */
00159 
00160               if (!configt_islocal(p->next, &hostdomain))
00161               {
00162                      (*nextfunc)(rwi);
00163                      return;
00164               }
00165 
00166               if (hostdomain)
00167               {
00168                      char *pp;
00169 
00170                      p->next= &hostdomaint;
00171 
00172                      for (pp=hostdomain; *pp; pp++)
00173                             *pp=tolower((int)(unsigned char)*pp);
00174 
00175                      hostdomaint.next=0;
00176                      hostdomaint.token=0;
00177                      hostdomaint.ptr=hostdomain;
00178                      hostdomaint.len=strlen(hostdomain);
00179               }
00180               else
00181                      *prevp=0;
00182        }
00183 
00184        /* Remove quotes from the local portion */
00185 
00186        for (p=rwi->ptr; p; p=p->next)
00187               if (p->token == '"') p->token=0;
00188        addr=rfc822_gettok(rwi->ptr);
00189 
00190        if (!addr)    clog_msg_errno();
00191        locallower(addr);
00192 
00193        if (strchr(addr, '!') || *addr == 0)
00194        {
00195               /* Can't have !s in an address, that's used a delimiter
00196               ** for the returned data.
00197               ** Can't have NULL addresses either.
00198               */
00199 
00200               goto not_found;
00201        }
00202 
00203        /*
00204        ** We do not accept local addresses that start with a period.  That is
00205        ** reserved for legacy alias handling.  If this is called from
00206        ** submit, we reject explicit addresses of that form.  These addresses
00207        ** are expanded from aliases, and then are inserted without calling
00208        ** the rewriting functions.  Subsequently we get here when
00209        ** we're in courierd, but RW_SUBMIT is not set.
00210        */
00211 
00212        if (*addr == '.')
00213        {
00214               if ((rwi->mode & (RW_SUBMIT|RW_SUBMITALIAS))
00215                      == RW_SUBMIT)
00216                      goto not_found;             /* Sorry */
00217 
00218               goto toalias;               /* Sorry again */
00219        }
00220 
00221 #if LOCAL_EXTENSIONS
00222        atdomain=strrchr(addr, '@');
00223        if (atdomain)
00224               *atdomain++=0;
00225 #endif
00226 
00227        i=0;
00228        for (ext=addr; *ext; ext++)
00229        {
00230 #if LOCAL_EXTENSIONS
00231               if (*ext == '-' && ++i > 3)
00232                      break;
00233 #endif
00234        }
00235 
00236        for (;;)
00237        {
00238        char *search_addr=addr;
00239 
00240 #if LOCAL_EXTENSIONS
00241        char   c;
00242        char *alloc_buf=0;
00243 
00244               c= *ext;
00245               *ext=0;
00246 
00247               lai.ext=c ? ext+1:ext;
00248 
00249               if (atdomain)
00250               {
00251                      alloc_buf=malloc(strlen(addr)+strlen(atdomain)+2);
00252                      if (!alloc_buf)
00253                             clog_msg_errno();
00254                      strcat(strcat(strcpy(alloc_buf, addr), "@"),
00255                             atdomain);
00256                      search_addr=alloc_buf;
00257               }
00258 #else
00259               lai.ext=0;
00260 #endif
00261               lai.address=search_addr;
00262               lai.delfunc=delfunc;
00263               lai.rwi=rwi;
00264               lai.found=0;
00265 
00266               i=auth_getuserinfo("courier", search_addr,
00267                                local_callback, &lai);
00268 
00269 #if LOCAL_EXTENSIONS
00270               if (alloc_buf)
00271                      free(alloc_buf);
00272 #endif
00273               if (i == 0)
00274               {
00275                      if (lai.exists)
00276                      {
00277                             free(addr);
00278                             if (hostdomain)      free(hostdomain);
00279                             return;
00280                      }
00281                      goto not_found;
00282               }
00283 
00284               if (i > 0)
00285               {
00286                      free(addr);
00287                      if (hostdomain)      free(hostdomain);
00288                      (*rwi->err_func)(450,
00289                             "Service temporarily unavailable.", rwi);
00290                      return;
00291               }
00292 #if LOCAL_EXTENSIONS
00293               *ext=c;
00294 
00295               while (ext > addr)
00296                      if (*--ext == '-')   break;
00297               if (ext == addr)
00298               {
00299                      if (atdomain)
00300                      {
00301                             lai.ext=addr;
00302                             lai.delfunc=delfunc;
00303                             lai.rwi=rwi;
00304                             lai.found=0;
00305 
00306                             alloc_buf=malloc(sizeof(DEFAULTNAME)
00307                                            +strlen(atdomain));
00308                             if (!alloc_buf)
00309                                    clog_msg_errno();
00310 
00311                             strcat(strcpy(alloc_buf, DEFAULTNAME),
00312                                    atdomain);
00313 
00314                             i=auth_getuserinfo("courier",
00315                                              alloc_buf,
00316                                              &local_callback, &lai);
00317                             free(alloc_buf);
00318                             if (i == 0)
00319                             {
00320                                    if (lai.exists)
00321                                    {
00322                                           free(addr);
00323                                           if (hostdomain)
00324                                                  free(hostdomain);
00325                                           return;
00326                                    }
00327                                    goto not_found;
00328                             }
00329                             if (i > 0)
00330                             {
00331                                    free(addr);
00332                                    if (hostdomain)      free(hostdomain);
00333                                    (*rwi->err_func)(450,
00334                                                   "Service temporarily unavailable.", rwi);
00335                                    return;
00336                             }
00337                      }
00338                      break;
00339               }
00340 #else
00341               break;
00342 #endif
00343        }
00344 
00345 #if LOCAL_EXTENSIONS
00346        if (atdomain)
00347               atdomain[-1]='@';    /* Put back what was taken */
00348 #endif
00349 
00350        /* Try to deliver to an alias defined in ${sysconfdir}/aliasdir */
00351 
00352 toalias:
00353 
00354        {
00355        struct authinfo aa;
00356        static const uid_t   mailuid=MAILUID;
00357 
00358               memset(&aa, 0, sizeof(aa));
00359               aa.homedir= ALIASDIR;
00360               aa.sysuserid= &mailuid;
00361               aa.sysgroupid=MAILGID;
00362               lai.address=aa.address="alias";
00363 
00364               lai.ext=addr;
00365               lai.delfunc=delfunc;
00366               lai.rwi=rwi;
00367               lai.found=0;
00368 
00369               i=local_callback( &aa, &lai );
00370 
00371               if (i == 0)
00372               {
00373                      if (lai.exists)
00374                      {
00375                             free(addr);
00376                             if (hostdomain)      free(hostdomain);
00377                             return;
00378                      }
00379                      goto not_found;
00380               }
00381 
00382               if (i > 0)
00383               {
00384                      free(addr);
00385                      if (hostdomain)      free(hostdomain);
00386                      (*rwi->err_func)(450,
00387                             "Service temporarily unavailable.", rwi);
00388                      return;
00389               }
00390        }
00391 
00392 not_found:
00393        /*
00394        ** When submit is being called by the sendmail command line,
00395        ** don't reject unknown addresses, instead accept them (and bounce
00396        ** them later, when we get here from courierd's main loop).
00397        ** Otherwise, couriermlm will barf when a local address disappears.
00398        */
00399 
00400        if ((rwi->mode & (RW_SUBMIT|RW_EXPN|RW_VERIFY)) == RW_SUBMIT &&
00401            rwi->smodule &&
00402            (strcmp(rwi->smodule, "local") == 0 ||
00403             strcmp(rwi->smodule, "uucp") == 0))
00404        {
00405               free(addr);
00406               (*delfunc)(rwi, rwi->ptr, rwi->ptr);
00407               if (hostdomain)      free(hostdomain);
00408 
00409               return;
00410        }
00411 
00412        {
00413               char buf[256];
00414 
00415               char *orig_addr=rfc822_gettok(rwi->ptr);
00416 
00417               buf[255]=0;
00418 
00419               snprintf(buf, 255, "User <%s> unknown",
00420                       orig_addr ? orig_addr:"");
00421               free(addr);
00422               if (hostdomain)      free(hostdomain);
00423 
00424               if (orig_addr)
00425                      free(orig_addr);
00426               (*rwi->err_func)(550, buf, rwi);
00427        }
00428        return;
00429 }
00430 
00431 
00432 static int local_callback(struct authinfo *a, void *vp)
00433 {
00434 struct localauthinfo *lai=(struct localauthinfo *)vp;
00435 struct rfc822token tacct, text, tuid, tgid, thomedir, tmaildir, tquota, trecip;
00436 struct rfc822token te1, te2, te3, te4, te5, te6;
00437 char   ubuf[40], gbuf[40];
00438 char   *p;
00439 uid_t  un;
00440 gid_t  gn;
00441 
00442        lai->found=1;
00443        lai->exists=0;
00444 
00445        if (lai->ext && *lai->ext)
00446        {
00447        char   *ext=local_dotcourier(a->homedir, lai->ext, 0);
00448 
00449               if (!ext && errno == ENOENT)
00450                      return (0);   /* Not found */
00451 
00452               if (ext)      free(ext);
00453        }
00454        if (a->homedir == 0 || strchr(a->homedir, '\n') ||
00455               strchr(a->homedir, '!') ||
00456               (a->maildir && (strchr(a->maildir, '\n') ||
00457                      strchr(a->maildir, '!'))))
00458        {
00459               syslog(LOG_DAEMON|LOG_CRIT,
00460                      "Invalid homedir or maildir for %s - has \\n, !, is null.",
00461                             lai->address);
00462               return (1);
00463        }
00464 
00465        lai->exists=1;
00466 /*
00467        Ok, we return the following information:
00468 
00469 Host:
00470 
00471        account ! ext ! uid ! gid ! homedir ! maildir ! quota
00472 
00473 Ext:
00474        non standard mailbox
00475 */
00476        tacct.next= &te1;
00477        tacct.token=0;
00478        tacct.ptr=a->address;
00479        tacct.len=strlen(tacct.ptr);
00480 
00481        te1.next= &text;
00482        te1.token='!';
00483        te1.ptr="!";
00484        te1.len=1;
00485 
00486        text.next= &te2;
00487        text.token=0;
00488        text.ptr=lai->ext;
00489        if (text.ptr == 0)   text.ptr="";
00490        text.len=strlen(text.ptr);
00491 
00492        te2.next= &tuid;
00493        te2.token='!';
00494        te2.ptr="!";
00495        te2.len=1;
00496 
00497        if (a->sysuserid)
00498               un= *a->sysuserid;
00499        else
00500        {
00501        struct passwd *pw=getpwnam(a->sysusername);
00502 
00503               if (!pw)
00504               {
00505                      syslog(LOG_DAEMON|LOG_CRIT,
00506                             "getpw(%s) failed - returned by authlib.",
00507                                    a->sysusername);
00508 
00509                      return (1);
00510               }
00511               un= pw->pw_uid;
00512        }
00513 
00514 #if ALLOW_ROOT
00515 
00516 #else
00517        if (un == 0)
00518        {
00519               return (-1);         /* Do not deliver to root */
00520        }
00521 #endif
00522        gn=a->sysgroupid;
00523 
00524        p=ubuf+sizeof(ubuf)-1;
00525        *p=0;
00526 
00527        do
00528        {
00529               *--p= "0123456789"[ un % 10];
00530               un=un/10;
00531        } while (un);
00532 
00533        tuid.next=&te3;
00534        tuid.token=0;
00535        tuid.ptr=p;
00536        tuid.len=strlen(p);
00537 
00538        te3.next= &tgid;
00539        te3.token='!';
00540        te3.ptr="!";
00541        te3.len=1;
00542 
00543        p=gbuf+sizeof(gbuf)-1;
00544        *p=0;
00545        do
00546        {
00547               *--p= "0123456789"[ gn % 10];
00548               gn=gn/10;
00549        } while (gn);
00550 
00551        tgid.next= &te4;
00552        tgid.token=0;
00553        tgid.ptr=p;
00554        tgid.len=strlen(p);
00555 
00556        te4.next= &thomedir;
00557        te4.token='!';
00558        te4.ptr="!";
00559        te4.len=1;
00560 
00561        thomedir.next=&te5;
00562        thomedir.token=0;
00563        thomedir.ptr= a->homedir;
00564        thomedir.len=strlen(thomedir.ptr);
00565 
00566        te5.next= &tmaildir;
00567        te5.token='!';
00568        te5.ptr="!";
00569        te5.len=1;
00570 
00571        tmaildir.next=&te6;
00572        tmaildir.token=0;
00573        tmaildir.ptr= a->maildir;
00574        if (tmaildir.ptr == 0)      tmaildir.ptr="";
00575        tmaildir.len=strlen(tmaildir.ptr);
00576 
00577        te6.next= &tquota;
00578        te6.token='!';
00579        te6.ptr="!";
00580 
00581        tquota.next=0;
00582        tquota.token=0;
00583        tquota.ptr= a->quota;
00584        if (tquota.ptr == 0) tquota.ptr="";
00585        tquota.len=strlen(tquota.ptr);
00586 
00587        trecip.next=0;
00588        trecip.token=0;
00589        trecip.ptr=lai->address;
00590        trecip.len=strlen(trecip.ptr);
00591 
00592        (*lai->delfunc)(lai->rwi, &tacct, &trecip);
00593        return (0);
00594 }
00595 
00596 /*
00597 ** Reject messages to local recipients based upon local criteria.
00598 **
00599 ** The difference between this and the check in rw_del_local is that
00600 ** this is performed after the message has been received, so we
00601 ** now have the message contents available.
00602 **
00603 ** To reject the message to this receipient, return a negative value
00604 ** for a permenant rejection, and a positive value for a temporary
00605 ** rejection (currently unused due to limitations in SMTP).
00606 **
00607 ** To accept the message, return 0.
00608 **
00609 ** Optional descriptive text can be saved in 'buf', whose size in bytes
00610 ** is given by bufsize.
00611 */
00612 
00613 static int rw_local_filter(const char *smodule,
00614                      int fd,
00615                      const char *host,
00616                      const char *addr,
00617                      const char *sender,
00618                      char *buf,
00619                      unsigned bufsize)
00620 {
00621 int    p[2];
00622 pid_t  pid;
00623 const  char *maildrop;
00624 char   errbuf[256];
00625 int    l;
00626 char   *s, *t;
00627 const char *uidgids;
00628 const char *homedir;
00629 const char *defaults;
00630 const char *quota;
00631 
00632        if ((maildrop=config_maildropfilter()) == 0 || *maildrop != '/')
00633               return (0);
00634 
00635        /* host is account!ext!blah... */
00636 
00637        s=strdup(host);
00638        if (!s)
00639        {
00640               strcpy(buf, "450 malloc() failed.");
00641               return (1);
00642        }
00643        
00644        host=s;
00645 
00646        t=strchr(s, '!');
00647        if (!t)
00648        {
00649               free(s);
00650               return (0);
00651        }
00652        *t++=0;
00653        addr=t;
00654        t=strchr(t, '!');
00655        if (!t)
00656        {
00657               free(s);
00658               return (0);
00659        }
00660        *t++=0;
00661        uidgids=t;
00662        t=strchr(t, '!');
00663        if (!t)
00664        {
00665               free(s);
00666               return (0);
00667        }
00668        *t++ = '/';
00669        t=strchr(t, '!');
00670        if (!t)
00671        {
00672               free(s);
00673               return (0);
00674        }
00675        *t++=0;
00676        homedir=t;
00677        t=strchr(t, '!');
00678        if (!t)
00679        {
00680               free(s);
00681               return (0);
00682        }
00683        *t++=0;
00684        defaults=t;
00685        t=strchr(t, '!');
00686        if (!t)
00687        {
00688               free(s);
00689               return (0);
00690        }
00691        *t++=0;
00692        quota=t;
00693 
00694        if (pipe(p) < 0)
00695        {
00696               free(s);
00697               strcpy(buf, "450 pipe() failed.");
00698               return (1);
00699        }
00700 
00701        if ((pid=fork()) < 0)
00702        {
00703               free(s);
00704               strcpy(buf, "450 fork() failed.");
00705               return (1);
00706        }
00707 
00708        if (pid == 0)
00709        {
00710        char   *argv[11];
00711 
00712               close(0);
00713               if (fd < 0)
00714                      open("/dev/null", O_RDONLY);
00715               else
00716               {
00717                      dup2(fd, 0);
00718                      close(fd);
00719               }
00720               dup2(p[1], 1);
00721               dup2(p[1], 2);
00722               close(p[0]);
00723               close(p[1]);
00724 
00725               argv[0]=strrchr(maildrop, '/')+1;
00726               argv[1]="-D";
00727               argv[2]=(char *)uidgids;
00728               argv[3]="-M";
00729               argv[4]=malloc((addr ? strlen(addr):0)+sizeof("smtpfilter-"));
00730               if (!argv[4])
00731               {
00732                      printf("450 Out of memory.\n");
00733                      fflush(stdout);
00734                      _exit(0);
00735               }
00736               strcpy(argv[4], fd < 0 ? "rcptfilter":"smtpfilter");
00737               if (addr && *addr)
00738                      strcat(strcat(argv[4], "-"), addr);
00739               argv[5]=getenv("TCPREMOTEHOST");
00740               if (!argv[5]) argv[5]="";
00741               argv[6]=getenv("TCPREMOTEIP");
00742               if (!argv[6]) argv[6]="";
00743               argv[7]=(char *)sender;
00744               if (!argv[7]) argv[7]="";
00745               putenv(strcat(strcpy(courier_malloc(sizeof("SENDER=")+
00746                                    strlen(argv[7])), "SENDER="),
00747                                    argv[7]));
00748 
00749               putenv(strcat(strcpy(courier_malloc(sizeof("HOME=")+
00750                      strlen(homedir)), "HOME="), homedir));
00751               putenv(strcat(strcpy(courier_malloc(sizeof("DEFAULT=")+
00752                      strlen(defaults)), "DEFAULT="), defaults));
00753               putenv(strcat(strcpy(courier_malloc(sizeof("MAILDIRQUOTA=")+
00754                      strlen(quota)), "MAILDIRQUOTA="), quota));
00755 
00756 
00757               argv[8]=getenv("BOUNCE");
00758               if (!argv[8]) argv[8]="";
00759               argv[9]=getenv("BOUNCE2");
00760               if (!argv[9]) argv[9]="";
00761               argv[10]=0;
00762               execv(maildrop, argv);
00763               _exit(0);     /* Assume spam filter isn't installed */
00764        }
00765        free(s);
00766 
00767        close(p[1]);
00768 
00769        while ((l=read(p[0], errbuf, sizeof(errbuf))) > 0)
00770        {
00771               if (l > bufsize-1)
00772                      l=bufsize-1;
00773               memcpy(buf, errbuf, l);
00774               buf += l;
00775               bufsize -= l;
00776        }
00777        close(p[0]);
00778        *buf=0;
00779 
00780        while (wait(&l) != pid)
00781               ;
00782 
00783        if (WIFEXITED(l))
00784               return (WEXITSTATUS(l));
00785 
00786        return (1);
00787 }